summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/extension_action/browser_action_apitest.cc1
-rw-r--r--chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc4
-rw-r--r--chrome/browser/extensions/api/extension_action/extension_action_api.cc8
-rw-r--r--chrome/browser/extensions/browser_context_keyed_service_factories.cc4
-rw-r--r--chrome/browser/extensions/extension_action_test_util.cc57
-rw-r--r--chrome/browser/extensions/extension_action_test_util.h8
-rw-r--r--chrome/browser/extensions/extension_message_bubble_controller.cc8
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.cc753
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.h277
-rw-r--r--chrome/browser/extensions/extension_toolbar_model_factory.cc59
-rw-r--r--chrome/browser/extensions/extension_toolbar_model_unittest.cc1210
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm8
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm2
-rw-r--r--chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.cc7
-rw-r--r--chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc10
-rw-r--r--chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h6
-rw-r--r--chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc58
-rw-r--r--chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc42
-rw-r--r--chrome/browser/ui/toolbar/component_toolbar_actions_factory.h20
-rw-r--r--chrome/browser/ui/toolbar/media_router_action.cc28
-rw-r--r--chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc32
-rw-r--r--chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h32
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_bar.cc118
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_bar.h39
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc2
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.h8
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_model.cc844
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_model.h311
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc55
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_model_factory.h (renamed from chrome/browser/extensions/extension_toolbar_model_factory.h)24
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc1369
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model.cc20
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model.h4
-rw-r--r--chrome/browser/ui/views/toolbar/browser_actions_container.cc6
-rw-r--r--chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc28
-rw-r--r--chrome/browser/ui/views/toolbar/chevron_menu_button.cc1
-rw-r--r--chrome/chrome_browser_extensions.gypi8
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi4
-rw-r--r--chrome/common/chrome_switches.cc2
-rw-r--r--tools/metrics/histograms/histograms.xml32
41 files changed, 2910 insertions, 2601 deletions
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 32eeae5..0dfc4a8 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -10,7 +10,6 @@
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
index 8d1b322..66cfc28 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -7,7 +7,6 @@
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
@@ -15,6 +14,7 @@
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_service.h"
@@ -102,7 +102,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
ui::PAGE_TRANSITION_TYPED, false)));
// Hide all the buttons to test that it opens even when the browser action
// is in the overflow bucket.
- extensions::ExtensionToolbarModel::Get(profile())->SetVisibleIconCount(0);
+ ToolbarActionsModel::Get(profile())->SetVisibleIconCount(0);
frame_observer.Wait();
}
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 8c151a9..0736edff 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -13,7 +13,6 @@
#include "chrome/browser/extensions/active_script_controller.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
@@ -23,6 +22,7 @@
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/common/extensions/api/extension_action/action_info.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/event_router.h"
@@ -228,9 +228,9 @@ bool ExtensionActionAPI::ShowExtensionActionPopup(
return browser->window()->GetLocationBar()->ShowPageActionPopup(
extension, grant_active_tab_permissions);
} else {
- return ExtensionToolbarModel::Get(browser->profile())->
- ShowExtensionActionPopup(
- extension, browser, grant_active_tab_permissions);
+ return ToolbarActionsModel::Get(browser->profile())
+ ->ShowToolbarActionPopup(extension->id(), browser,
+ grant_active_tab_permissions);
}
}
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index f97a4be..934390d 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -47,7 +47,6 @@
#include "chrome/browser/extensions/extension_gcm_app_handler.h"
#include "chrome/browser/extensions/extension_storage_monitor_factory.h"
#include "chrome/browser/extensions/extension_system_factory.h"
-#include "chrome/browser/extensions/extension_toolbar_model_factory.h"
#include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
#include "chrome/browser/extensions/install_tracker_factory.h"
#include "chrome/browser/extensions/install_verifier_factory.h"
@@ -56,6 +55,7 @@
#include "chrome/browser/extensions/token_cache/token_cache_service_factory.h"
#include "chrome/browser/extensions/warning_badge_service_factory.h"
#include "chrome/browser/speech/extension_api/tts_extension_api.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h"
@@ -89,7 +89,6 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
extensions::ExtensionGarbageCollectorFactory::GetInstance();
extensions::ExtensionStorageMonitorFactory::GetInstance();
extensions::ExtensionSystemFactory::GetInstance();
- extensions::ExtensionToolbarModelFactory::GetInstance();
extensions::ExtensionWebUIOverrideRegistrar::GetFactoryInstance();
extensions::FeedbackPrivateAPI::GetFactoryInstance();
extensions::FontSettingsAPI::GetFactoryInstance();
@@ -141,6 +140,7 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
file_manager::EventRouterFactory::GetInstance();
#endif
TokenCacheServiceFactory::GetInstance();
+ ToolbarActionsModelFactory::GetInstance();
extensions::ExtensionGCMAppHandler::GetFactoryInstance();
}
diff --git a/chrome/browser/extensions/extension_action_test_util.cc b/chrome/browser/extensions/extension_action_test_util.cc
index 6a6eddc..1a9de97 100644
--- a/chrome/browser/extensions/extension_action_test_util.cc
+++ b/chrome/browser/extensions/extension_action_test_util.cc
@@ -8,15 +8,16 @@
#include "base/run_loop.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/extensions/extension_toolbar_model_factory.h"
#include "chrome/browser/extensions/location_bar_controller.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/extensions/test_extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
#include "components/crx_file/id_util.h"
#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/feature_switch.h"
@@ -35,7 +36,7 @@ size_t GetPageActionCount(content::WebContents* web_contents,
int tab_id = SessionTabHelper::IdForTab(web_contents);
// Page actions are either stored in the location bar (and provided by the
// LocationBarController), or in the main toolbar (and provided by the
- // ExtensionToolbarModel), depending on whether or not the extension action
+ // ToolbarActionsModel), depending on whether or not the extension action
// redesign is enabled.
if (!FeatureSwitch::extension_action_redesign()->IsEnabled()) {
std::vector<ExtensionAction*> page_actions =
@@ -51,44 +52,50 @@ size_t GetPageActionCount(content::WebContents* web_contents,
}
}
} else {
- ExtensionToolbarModel* toolbar_model =
- ExtensionToolbarModel::Get(
- Profile::FromBrowserContext(web_contents->GetBrowserContext()));
- const ExtensionList& toolbar_extensions = toolbar_model->toolbar_items();
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents->GetBrowserContext());
+ ToolbarActionsModel* toolbar_model = ToolbarActionsModel::Get(profile);
+ const std::vector<ToolbarActionsModel::ToolbarItem>& toolbar_items =
+ toolbar_model->toolbar_items();
ExtensionActionManager* action_manager =
ExtensionActionManager::Get(web_contents->GetBrowserContext());
- for (ExtensionList::const_iterator iter = toolbar_extensions.begin();
- iter != toolbar_extensions.end(); ++iter) {
- ExtensionAction* extension_action = action_manager->GetPageAction(**iter);
- if (extension_action &&
- (!only_count_visible || extension_action->GetIsVisible(tab_id)))
- ++count;
+ for (const ToolbarActionsModel::ToolbarItem& item : toolbar_items) {
+ if (item.type == ToolbarActionsModel::EXTENSION_ACTION) {
+ const Extension* extension =
+ ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+ item.id);
+ ExtensionAction* extension_action =
+ action_manager->GetPageAction(*extension);
+ if (extension_action &&
+ (!only_count_visible || extension_action->GetIsVisible(tab_id)))
+ ++count;
+ }
}
}
return count;
}
-// Creates a new ExtensionToolbarModel for the given |context|.
+// Creates a new ToolbarActionsModel for the given |context|.
scoped_ptr<KeyedService> BuildToolbarModel(content::BrowserContext* context) {
- return make_scoped_ptr(new extensions::ExtensionToolbarModel(
- Profile::FromBrowserContext(context),
- extensions::ExtensionPrefs::Get(context)));
+ return make_scoped_ptr(
+ new ToolbarActionsModel(Profile::FromBrowserContext(context),
+ extensions::ExtensionPrefs::Get(context)));
}
-// Creates a new ExtensionToolbarModel for the given profile, optionally
+// Creates a new ToolbarActionsModel for the given profile, optionally
// triggering the extension system's ready signal.
-ExtensionToolbarModel* CreateToolbarModelImpl(Profile* profile,
- bool wait_for_ready) {
- ExtensionToolbarModel* model = ExtensionToolbarModel::Get(profile);
+ToolbarActionsModel* CreateToolbarModelImpl(Profile* profile,
+ bool wait_for_ready) {
+ ToolbarActionsModel* model = ToolbarActionsModel::Get(profile);
if (model)
return model;
// No existing model means it's a new profile (since we, by default, don't
// create the ToolbarModel in testing).
- ExtensionToolbarModelFactory::GetInstance()->SetTestingFactory(
+ ToolbarActionsModelFactory::GetInstance()->SetTestingFactory(
profile, &BuildToolbarModel);
- model = ExtensionToolbarModel::Get(profile);
+ model = ToolbarActionsModel::Get(profile);
if (wait_for_ready) {
// Fake the extension system ready signal.
// HACK ALERT! In production, the ready task on ExtensionSystem (and most
@@ -151,11 +158,11 @@ scoped_refptr<const Extension> CreateActionExtension(
Build();
}
-ExtensionToolbarModel* CreateToolbarModelForProfile(Profile* profile) {
+ToolbarActionsModel* CreateToolbarModelForProfile(Profile* profile) {
return CreateToolbarModelImpl(profile, true);
}
-ExtensionToolbarModel* CreateToolbarModelForProfileWithoutWaitingForReady(
+ToolbarActionsModel* CreateToolbarModelForProfileWithoutWaitingForReady(
Profile* profile) {
return CreateToolbarModelImpl(profile, false);
}
diff --git a/chrome/browser/extensions/extension_action_test_util.h b/chrome/browser/extensions/extension_action_test_util.h
index 0d52726..7f5a7e2 100644
--- a/chrome/browser/extensions/extension_action_test_util.h
+++ b/chrome/browser/extensions/extension_action_test_util.h
@@ -12,6 +12,7 @@
#include "extensions/common/manifest.h"
class Profile;
+class ToolbarActionsModel;
namespace content {
class WebContents;
@@ -19,7 +20,6 @@ class WebContents;
namespace extensions {
class Extension;
-class ExtensionToolbarModel;
namespace extension_action_test_util {
@@ -51,15 +51,15 @@ scoped_refptr<const Extension> CreateActionExtension(
ActionType action_type,
Manifest::Location location);
-// Creates a new ExtensionToolbarModel for the given |profile|, and associates
+// Creates a new ToolbarActionsModel for the given |profile|, and associates
// it with the profile as a keyed service.
// This should only be used in unit tests (since it assumes the existence of
// a TestExtensionSystem), but if running a browser test, the model should
// already be created.
-ExtensionToolbarModel* CreateToolbarModelForProfile(Profile* profile);
+ToolbarActionsModel* CreateToolbarModelForProfile(Profile* profile);
// Like above, but doesn't run the ExtensionSystem::ready() task for the new
// model.
-ExtensionToolbarModel* CreateToolbarModelForProfileWithoutWaitingForReady(
+ToolbarActionsModel* CreateToolbarModelForProfileWithoutWaitingForReady(
Profile* profile);
} // namespace extension_action_test_util
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.cc b/chrome/browser/extensions/extension_message_bubble_controller.cc
index 9c2430a..3fe6dc5 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller.cc
@@ -10,10 +10,10 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_message_bubble.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/user_metrics.h"
#include "extensions/browser/extension_prefs.h"
@@ -162,8 +162,8 @@ void ExtensionMessageBubbleController::HighlightExtensionsIfNecessary() {
did_highlight_ = true;
const ExtensionIdList& extension_ids = GetExtensionIdList();
DCHECK(!extension_ids.empty());
- ExtensionToolbarModel::Get(profile())->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
+ ToolbarActionsModel::Get(profile())->HighlightActions(
+ extension_ids, ToolbarActionsModel::HIGHLIGHT_WARNING);
}
}
@@ -248,7 +248,7 @@ ExtensionIdList* ExtensionMessageBubbleController::GetOrCreateExtensionList() {
void ExtensionMessageBubbleController::OnClose() {
AcknowledgeExtensions();
if (did_highlight_)
- ExtensionToolbarModel::Get(profile())->StopHighlighting();
+ ToolbarActionsModel::Get(profile())->StopHighlighting();
}
} // namespace extensions
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
deleted file mode 100644
index bad9027..0000000
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ /dev/null
@@ -1,753 +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/extensions/extension_toolbar_model.h"
-
-#include <algorithm>
-#include <string>
-
-#include "base/location.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_base.h"
-#include "base/prefs/pref_service.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/extensions/extension_toolbar_model_factory.h"
-#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.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/pref_names.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/extension_set.h"
-#include "extensions/common/feature_switch.h"
-#include "extensions/common/manifest_constants.h"
-#include "extensions/common/one_shot_event.h"
-
-namespace extensions {
-
-ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile,
- ExtensionPrefs* extension_prefs)
- : profile_(profile),
- extension_prefs_(extension_prefs),
- prefs_(profile_->GetPrefs()),
- extension_action_api_(ExtensionActionAPI::Get(profile_)),
- extensions_initialized_(false),
- include_all_extensions_(FeatureSwitch::extension_action_redesign()
- ->IsEnabled()),
- highlight_type_(HIGHLIGHT_NONE),
- extension_action_observer_(this),
- extension_registry_observer_(this),
- weak_ptr_factory_(this) {
- ExtensionSystem::Get(profile_)->ready().Post(
- FROM_HERE,
- base::Bind(&ExtensionToolbarModel::OnReady,
- weak_ptr_factory_.GetWeakPtr()));
- visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize);
-
- // We only care about watching the prefs if not in incognito mode.
- if (!profile_->IsOffTheRecord()) {
- pref_change_registrar_.Init(prefs_);
- pref_change_callback_ =
- base::Bind(&ExtensionToolbarModel::OnExtensionToolbarPrefChange,
- base::Unretained(this));
- pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
- }
-}
-
-ExtensionToolbarModel::~ExtensionToolbarModel() {
-}
-
-// static
-ExtensionToolbarModel* ExtensionToolbarModel::Get(Profile* profile) {
- return ExtensionToolbarModelFactory::GetForProfile(profile);
-}
-
-void ExtensionToolbarModel::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void ExtensionToolbarModel::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void ExtensionToolbarModel::MoveExtensionIcon(const std::string& id,
- size_t index) {
- ExtensionList::iterator pos = toolbar_items_.begin();
- while (pos != toolbar_items_.end() && (*pos)->id() != id)
- ++pos;
- if (pos == toolbar_items_.end()) {
- NOTREACHED();
- return;
- }
- scoped_refptr<const Extension> extension = *pos;
- toolbar_items_.erase(pos);
-
- ExtensionIdList::iterator pos_id = std::find(last_known_positions_.begin(),
- last_known_positions_.end(),
- id);
- if (pos_id != last_known_positions_.end())
- last_known_positions_.erase(pos_id);
-
- if (index < toolbar_items_.size()) {
- // If the index is not at the end, find the item currently at |index|, and
- // insert |extension| before it in both |toolbar_items_| and
- // |last_known_positions_|.
- ExtensionList::iterator iter = toolbar_items_.begin() + index;
- last_known_positions_.insert(std::find(last_known_positions_.begin(),
- last_known_positions_.end(),
- (*iter)->id()),
- id);
- toolbar_items_.insert(iter, extension);
- } else {
- // Otherwise, put |extension| at the end.
- DCHECK_EQ(toolbar_items_.size(), index);
- index = toolbar_items_.size();
- toolbar_items_.push_back(extension);
- last_known_positions_.push_back(id);
- }
-
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarExtensionMoved(extension.get(), index));
- MaybeUpdateVisibilityPref(extension.get(), index);
- UpdatePrefs();
-}
-
-void ExtensionToolbarModel::SetVisibleIconCount(size_t count) {
- visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count;
-
- // Only set the prefs if we're not in highlight mode and the profile is not
- // incognito. Highlight mode is designed to be a transitory state, and should
- // not persist across browser restarts (though it may be re-entered), and we
- // don't store anything in incognito.
- if (!is_highlighting() && !profile_->IsOffTheRecord()) {
- // Additionally, if we are using the new toolbar, any icons which are in the
- // overflow menu are considered "hidden". But it so happens that the times
- // we are likely to call SetVisibleIconCount() are also those when we are
- // in flux. So wait for things to cool down before setting the prefs.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs,
- weak_ptr_factory_.GetWeakPtr()));
- prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_);
- }
-
- FOR_EACH_OBSERVER(Observer, observers_, OnToolbarVisibleCountChanged());
-}
-
-void ExtensionToolbarModel::OnExtensionActionUpdated(
- ExtensionAction* extension_action,
- content::WebContents* web_contents,
- content::BrowserContext* browser_context) {
- const Extension* extension =
- ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID(
- extension_action->extension_id());
- // Notify observers if the extension exists and is in the model.
- if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) !=
- toolbar_items_.end()) {
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarExtensionUpdated(extension));
- }
-}
-
-void ExtensionToolbarModel::OnExtensionActionVisibilityChanged(
- const std::string& extension_id,
- bool is_now_visible) {
- const Extension* extension =
- ExtensionRegistry::Get(profile_)->GetExtensionById(
- extension_id, ExtensionRegistry::EVERYTHING);
-
- // Hiding works differently with the new and old toolbars.
- if (include_all_extensions_) {
- // It's possible that we haven't added this extension yet, if its
- // visibility was adjusted in the course of its initialization.
- if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) ==
- toolbar_items_.end())
- return;
-
- int new_size = 0;
- int new_index = 0;
- if (is_now_visible) {
- // If this action used to be hidden, we can't possibly be showing all.
- DCHECK_LT(visible_icon_count(), toolbar_items_.size());
- // Grow the bar by one and move the extension to the end of the visibles.
- new_size = visible_icon_count() + 1;
- new_index = new_size - 1;
- } else {
- // If we're hiding one, we must be showing at least one.
- DCHECK_GE(visible_icon_count(), 0u);
- // Shrink the bar by one and move the extension to the beginning of the
- // overflow menu.
- new_size = visible_icon_count() - 1;
- new_index = new_size;
- }
- SetVisibleIconCount(new_size);
- MoveExtensionIcon(extension->id(), new_index);
- } else { // Don't include all extensions.
- if (is_now_visible)
- AddExtension(extension);
- else
- RemoveExtension(extension);
- }
-}
-
-void ExtensionToolbarModel::OnExtensionLoaded(
- content::BrowserContext* browser_context,
- const Extension* extension) {
- // We don't want to add the same extension twice. It may have already been
- // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user
- // hides the browser action and then disables and enables the extension.
- for (size_t i = 0; i < toolbar_items_.size(); i++) {
- if (toolbar_items_[i].get() == extension)
- return;
- }
-
- AddExtension(extension);
-}
-
-void ExtensionToolbarModel::OnExtensionUnloaded(
- content::BrowserContext* browser_context,
- const Extension* extension,
- UnloadedExtensionInfo::Reason reason) {
- RemoveExtension(extension);
-}
-
-void ExtensionToolbarModel::OnExtensionUninstalled(
- content::BrowserContext* browser_context,
- const Extension* extension,
- extensions::UninstallReason reason) {
- // Remove the extension id from the ordered list, if it exists (the extension
- // might not be represented in the list because it might not have an icon).
- ExtensionIdList::iterator pos =
- std::find(last_known_positions_.begin(),
- last_known_positions_.end(), extension->id());
-
- if (pos != last_known_positions_.end()) {
- last_known_positions_.erase(pos);
- UpdatePrefs();
- }
-}
-
-void ExtensionToolbarModel::OnReady() {
- ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
- InitializeExtensionList();
- // Wait until the extension system is ready before observing any further
- // changes so that the toolbar buttons can be shown in their stable ordering
- // taken from prefs.
- extension_registry_observer_.Add(registry);
- extension_action_observer_.Add(extension_action_api_);
-
- if (ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
- profile_)) {
- ExtensionIdList ids;
- for (const auto& extension : toolbar_items_)
- ids.push_back(extension->id());
- HighlightExtensions(ids, HIGHLIGHT_INFO);
- }
-
- extensions_initialized_ = true;
- FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized());
-}
-
-size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood(
- const Extension* extension) {
- // See if we have last known good position for this extension.
- size_t new_index = 0;
- // Loop through the ID list of known positions, to count the number of visible
- // extension icons preceding |extension|.
- for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin();
- iter_id < last_known_positions_.end(); ++iter_id) {
- if ((*iter_id) == extension->id())
- return new_index; // We've found the right position.
- // Found an id, need to see if it is visible.
- for (ExtensionList::const_iterator iter_ext = toolbar_items_.begin();
- iter_ext < toolbar_items_.end(); ++iter_ext) {
- if ((*iter_ext)->id() == (*iter_id)) {
- // This extension is visible, update the index value.
- ++new_index;
- break;
- }
- }
- }
-
- // Position not found.
- return toolbar_items_.size();
-}
-
-bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) {
- // In incognito mode, don't add any extensions that aren't incognito-enabled.
- if (profile_->IsOffTheRecord() &&
- !util::IsIncognitoEnabled(extension->id(), profile_))
- return false;
-
- ExtensionActionManager* action_manager =
- ExtensionActionManager::Get(profile_);
- if (include_all_extensions_) {
- // In this case, we don't care about the browser action visibility, because
- // we want to show each extension regardless.
- // TODO(devlin): Extension actions which are not visible should be moved to
- // the overflow menu by default.
- return action_manager->GetExtensionAction(*extension) != NULL;
- }
-
- return action_manager->GetBrowserAction(*extension) &&
- extension_action_api_->GetBrowserActionVisibility(extension->id());
-}
-
-void ExtensionToolbarModel::AddExtension(const Extension* extension) {
- // We only use AddExtension() once the system is initialized.
- DCHECK(extensions_initialized_);
- if (!ShouldAddExtension(extension))
- return;
-
- // See if we have a last known good position for this extension.
- bool is_new_extension =
- std::find(last_known_positions_.begin(),
- last_known_positions_.end(),
- extension->id()) == last_known_positions_.end();
-
- // New extensions go at the right (end) of the visible extensions. Other
- // extensions go at their previous position.
- size_t new_index = 0;
- if (is_new_extension) {
- new_index = Manifest::IsComponentLocation(extension->location()) ?
- 0 : visible_icon_count();
- // For the last-known position, we use the index of the extension that is
- // just before this extension, plus one. (Note that this isn't the same
- // as new_index + 1, because last_known_positions_ can include disabled
- // extensions.)
- int new_last_known_index =
- new_index == 0 ? 0 :
- std::find(last_known_positions_.begin(),
- last_known_positions_.end(),
- toolbar_items_[new_index - 1]->id()) -
- last_known_positions_.begin() + 1;
- // In theory, the extension before this one should always
- // be in last known positions, but if something funny happened with prefs,
- // make sure we handle it.
- // TODO(devlin): Track down these cases so we can CHECK this.
- new_last_known_index =
- std::min<int>(new_last_known_index, last_known_positions_.size());
- last_known_positions_.insert(
- last_known_positions_.begin() + new_last_known_index, extension->id());
- UpdatePrefs();
- } else {
- new_index = FindNewPositionFromLastKnownGood(extension);
- }
-
- toolbar_items_.insert(toolbar_items_.begin() + new_index, extension);
-
- // If we're currently highlighting, then even though we add a browser action
- // to the full list (|toolbar_items_|, there won't be another *visible*
- // browser action, which was what the observers care about.
- if (!is_highlighting()) {
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarExtensionAdded(extension, new_index));
-
- int visible_count_delta = 0;
- if (is_new_extension && !all_icons_visible()) {
- // If this is a new extension (and not all extensions are visible), we
- // expand the toolbar out so that the new one can be seen.
- visible_count_delta = 1;
- } else if (profile_->IsOffTheRecord()) {
- // If this is an incognito profile, we also have to check to make sure the
- // overflow matches the main bar's status.
- ExtensionToolbarModel* main_model =
- ExtensionToolbarModel::Get(profile_->GetOriginalProfile());
- // Find what the index will be in the main bar. Because Observer calls are
- // nondeterministic, we can't just assume the main bar will have the
- // extension and look it up.
- size_t main_index =
- main_model->FindNewPositionFromLastKnownGood(extension);
- bool visible = main_index < main_model->visible_icon_count();
- // We may need to adjust the visible count if the incognito bar isn't
- // showing all icons and this one is visible, or if it is showing all
- // icons and this is hidden.
- if (visible && !all_icons_visible())
- visible_count_delta = 1;
- else if (!visible && all_icons_visible())
- visible_count_delta = -1;
- }
-
- if (visible_count_delta)
- SetVisibleIconCount(visible_icon_count() + visible_count_delta);
- }
-
- MaybeUpdateVisibilityPref(extension, new_index);
-}
-
-void ExtensionToolbarModel::RemoveExtension(const Extension* extension) {
- ExtensionList::iterator pos =
- std::find(toolbar_items_.begin(), toolbar_items_.end(), extension);
- if (pos == toolbar_items_.end())
- return;
-
- size_t index = pos - toolbar_items_.begin();
- // If the removed extension was on the toolbar, a new one will take its place
- // if there are any in overflow.
- bool new_extension_shown =
- !all_icons_visible() && index < visible_icon_count();
-
- // If our visible count is set to the current size, we need to decrement it.
- if (visible_icon_count_ == static_cast<int>(toolbar_items_.size()))
- SetVisibleIconCount(toolbar_items_.size() - 1);
-
- toolbar_items_.erase(pos);
-
- // If we're in highlight mode, we also have to remove the extension from
- // the highlighted list.
- if (is_highlighting()) {
- pos = std::find(highlighted_items_.begin(),
- highlighted_items_.end(),
- extension);
- if (pos != highlighted_items_.end()) {
- highlighted_items_.erase(pos);
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarExtensionRemoved(extension));
- // If the highlighted list is now empty, we stop highlighting.
- if (highlighted_items_.empty())
- StopHighlighting();
- }
- } else {
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarExtensionRemoved(extension));
- }
-
- UpdatePrefs();
- if (new_extension_shown) {
- size_t newly_visible_index = visible_icon_count() - 1;
- MaybeUpdateVisibilityPref(toolbar_items_[newly_visible_index].get(),
- newly_visible_index);
- }
-}
-
-// Combine the currently enabled extensions that have browser actions (which
-// we get from the ExtensionRegistry) with the ordering we get from the
-// pref service. For robustness we use a somewhat inefficient process:
-// 1. Create a vector of extensions sorted by their pref values. This vector may
-// have holes.
-// 2. Create a vector of extensions that did not have a pref value.
-// 3. Remove holes from the sorted vector and append the unsorted vector.
-void ExtensionToolbarModel::InitializeExtensionList() {
- DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet.
-
- last_known_positions_ = extension_prefs_->GetToolbarOrder();
- if (profile_->IsOffTheRecord())
- IncognitoPopulate();
- else
- Populate(&last_known_positions_);
-
- MaybeUpdateVisibilityPrefs();
-}
-
-void ExtensionToolbarModel::Populate(ExtensionIdList* positions) {
- DCHECK(!profile_->IsOffTheRecord());
- const ExtensionSet& extensions =
- ExtensionRegistry::Get(profile_)->enabled_extensions();
- // Items that have explicit positions.
- ExtensionList sorted(positions->size(), NULL);
- // The items that don't have explicit positions.
- ExtensionList unsorted;
-
- // Create the lists.
- int hidden = 0;
- for (const scoped_refptr<const Extension>& extension : extensions) {
- if (!ShouldAddExtension(extension.get())) {
- if (!extension_action_api_->GetBrowserActionVisibility(extension->id()))
- ++hidden;
- continue;
- }
-
- ExtensionIdList::const_iterator pos =
- std::find(positions->begin(), positions->end(), extension->id());
- if (pos != positions->end()) {
- sorted[pos - positions->begin()] = extension;
- } else {
- // Unknown extension - push it to the back of unsorted, and add it to the
- // list of ids at the end.
- unsorted.push_back(extension);
- positions->push_back(extension->id());
- }
- }
-
- // Merge the lists.
- sorted.insert(sorted.end(), unsorted.begin(), unsorted.end());
- toolbar_items_.reserve(sorted.size());
-
- for (const scoped_refptr<const Extension>& extension : sorted) {
- // It's possible for the extension order to contain items that aren't
- // actually loaded on this machine. For example, when extension sync is on,
- // we sync the extension order as-is but double-check with the user before
- // syncing NPAPI-containing extensions, so if one of those is not actually
- // synced, we'll get a NULL in the list. This sort of case can also happen
- // if some error prevents an extension from loading.
- if (extension.get()) {
- // We don't notify observers of the added extension yet. Rather, observers
- // should wait for the "OnToolbarModelInitialized" notification, and then
- // bulk-update. (This saves a lot of bouncing-back-and-forth here, and
- // allows observers to ensure that the extension system is always
- // initialized before using the extensions).
- toolbar_items_.push_back(extension);
- }
- }
-
- UMA_HISTOGRAM_COUNTS_100(
- "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden);
- UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount",
- toolbar_items_.size());
-
- if (!toolbar_items_.empty()) {
- // Visible count can be -1, meaning: 'show all'. Since UMA converts negative
- // values to 0, this would be counted as 'show none' unless we convert it to
- // max.
- UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsVisible",
- visible_icon_count_ == -1 ?
- base::HistogramBase::kSampleType_MAX :
- visible_icon_count_);
- }
-}
-
-void ExtensionToolbarModel::IncognitoPopulate() {
- DCHECK(profile_->IsOffTheRecord());
- const ExtensionToolbarModel* original_model =
- ExtensionToolbarModel::Get(profile_->GetOriginalProfile());
-
- // Find the absolute value of the original model's count.
- int original_visible = original_model->visible_icon_count();
-
- // In incognito mode, we show only those extensions that are
- // incognito-enabled. Further, any actions that were overflowed in regular
- // mode are still overflowed. Order is the same as in regular mode.
- visible_icon_count_ = 0;
- for (ExtensionList::const_iterator iter =
- original_model->toolbar_items_.begin();
- iter != original_model->toolbar_items_.end(); ++iter) {
- if (ShouldAddExtension(iter->get())) {
- toolbar_items_.push_back(*iter);
- if (iter - original_model->toolbar_items_.begin() < original_visible)
- ++visible_icon_count_;
- }
- }
-}
-
-void ExtensionToolbarModel::UpdatePrefs() {
- if (!extension_prefs_ || profile_->IsOffTheRecord())
- return;
-
- // Don't observe change caused by self.
- pref_change_registrar_.Remove(pref_names::kToolbar);
- extension_prefs_->SetToolbarOrder(last_known_positions_);
- pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
-}
-
-void ExtensionToolbarModel::MaybeUpdateVisibilityPref(
- const Extension* extension, size_t index) {
- // We only update the visibility pref for hidden/not hidden based on the
- // overflow menu with the new toolbar design.
- if (include_all_extensions_ && !profile_->IsOffTheRecord()) {
- bool visible = index < visible_icon_count();
- if (visible != extension_action_api_->GetBrowserActionVisibility(
- extension->id())) {
- // Don't observe changes caused by ourselves.
- bool was_registered = false;
- if (extension_action_observer_.IsObserving(extension_action_api_)) {
- was_registered = true;
- extension_action_observer_.RemoveAll();
- }
- extension_action_api_->SetBrowserActionVisibility(extension->id(),
- visible);
- if (was_registered)
- extension_action_observer_.Add(extension_action_api_);
- }
- }
-}
-
-void ExtensionToolbarModel::MaybeUpdateVisibilityPrefs() {
- for (size_t i = 0u; i < toolbar_items_.size(); ++i)
- MaybeUpdateVisibilityPref(toolbar_items_[i].get(), i);
-}
-
-void ExtensionToolbarModel::OnExtensionToolbarPrefChange() {
- // If extensions are not ready, defer to later Populate() call.
- if (!extensions_initialized_)
- return;
-
- // Recalculate |last_known_positions_| to be |pref_positions| followed by
- // ones that are only in |last_known_positions_|.
- ExtensionIdList pref_positions = extension_prefs_->GetToolbarOrder();
- size_t pref_position_size = pref_positions.size();
- for (size_t i = 0; i < last_known_positions_.size(); ++i) {
- if (std::find(pref_positions.begin(), pref_positions.end(),
- last_known_positions_[i]) == pref_positions.end()) {
- pref_positions.push_back(last_known_positions_[i]);
- }
- }
- last_known_positions_.swap(pref_positions);
-
- int desired_index = 0;
- // Loop over the updated list of last known positions, moving any extensions
- // that are in the wrong place.
- for (const std::string& id : last_known_positions_) {
- int current_index = GetIndexForId(id);
- if (current_index == -1)
- continue;
- if (current_index != desired_index) {
- scoped_refptr<const Extension> extension = toolbar_items_[current_index];
- toolbar_items_.erase(toolbar_items_.begin() + current_index);
- toolbar_items_.insert(toolbar_items_.begin() + desired_index, extension);
- // Notify the observers to keep them up-to-date.
- FOR_EACH_OBSERVER(
- Observer, observers_,
- OnToolbarExtensionMoved(extension.get(), desired_index));
- }
- ++desired_index;
- }
-
- if (last_known_positions_.size() > pref_position_size) {
- // Need to update pref because we have extra icons. But can't call
- // UpdatePrefs() directly within observation closure.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&ExtensionToolbarModel::UpdatePrefs,
- weak_ptr_factory_.GetWeakPtr()));
- }
-}
-
-int ExtensionToolbarModel::GetIndexForId(const std::string& id) const {
- for (size_t i = 0; i < toolbar_items().size(); ++i) {
- if (toolbar_items()[i]->id() == id)
- return i;
- }
- return -1;
-}
-
-bool ExtensionToolbarModel::ShowExtensionActionPopup(
- const Extension* extension,
- Browser* browser,
- bool grant_active_tab) {
- base::ObserverListBase<Observer>::Iterator it(&observers_);
- Observer* obs = NULL;
- // Look for the Observer associated with the browser.
- // This would be cleaner if we had an abstract class for the Toolbar UI
- // (like we do for LocationBar), but sadly, we don't.
- while ((obs = it.GetNext()) != NULL) {
- if (obs->GetBrowser() == browser)
- return obs->ShowExtensionActionPopup(extension, grant_active_tab);
- }
- return false;
-}
-
-void ExtensionToolbarModel::EnsureVisibility(
- const ExtensionIdList& extension_ids) {
- if (all_icons_visible())
- return; // Already showing all.
-
- // Otherwise, make sure we have enough room to show all the extensions
- // requested.
- if (visible_icon_count() < extension_ids.size())
- SetVisibleIconCount(extension_ids.size());
-
- if (all_icons_visible())
- return; // May have been set to max by SetVisibleIconCount.
-
- // Guillotine's Delight: Move an orange noble to the front of the line.
- for (ExtensionIdList::const_iterator it = extension_ids.begin();
- it != extension_ids.end(); ++it) {
- for (ExtensionList::const_iterator extension = toolbar_items_.begin();
- extension != toolbar_items_.end(); ++extension) {
- if ((*extension)->id() == (*it)) {
- if (extension - toolbar_items_.begin() >=
- static_cast<int>(visible_icon_count()))
- MoveExtensionIcon((*extension)->id(), 0);
- break;
- }
- }
- }
-}
-
-bool ExtensionToolbarModel::HighlightExtensions(
- const ExtensionIdList& extension_ids,
- HighlightType highlight_type) {
- highlighted_items_.clear();
-
- for (ExtensionIdList::const_iterator id = extension_ids.begin();
- id != extension_ids.end();
- ++id) {
- for (ExtensionList::const_iterator extension = toolbar_items_.begin();
- extension != toolbar_items_.end();
- ++extension) {
- if (*id == (*extension)->id())
- highlighted_items_.push_back(*extension);
- }
- }
-
- // If we have any items in |highlighted_items_|, then we entered highlighting
- // mode.
- if (highlighted_items_.size()) {
- // It's important that is_highlighting_ is changed immediately before the
- // observers are notified since it changes the result of toolbar_items().
- highlight_type_ = highlight_type;
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarHighlightModeChanged(true));
-
- // We set the visible icon count after the highlight mode change because
- // the UI actions are created/destroyed during highlight, and doing that
- // prior to changing the size allows us to still have smooth animations.
- if (visible_icon_count() < extension_ids.size())
- SetVisibleIconCount(extension_ids.size());
-
- return true;
- }
-
- // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if
- // we were otherwise in it).
- if (is_highlighting())
- StopHighlighting();
- return false;
-}
-
-void ExtensionToolbarModel::StopHighlighting() {
- if (is_highlighting()) {
- // It's important that is_highlighting_ is changed immediately before the
- // observers are notified since it changes the result of toolbar_items().
- highlight_type_ = HIGHLIGHT_NONE;
- FOR_EACH_OBSERVER(Observer, observers_,
- OnToolbarHighlightModeChanged(false));
-
- // For the same reason, we don't clear highlighted_items_ until after the
- // mode changed.
- highlighted_items_.clear();
-
- // We set the visible icon count after the highlight mode change because
- // the UI actions are created/destroyed during highlight, and doing that
- // prior to changing the size allows us to still have smooth animations.
- int saved_icon_count = prefs_->GetInteger(pref_names::kToolbarSize);
- if (saved_icon_count != visible_icon_count_)
- SetVisibleIconCount(saved_icon_count);
- }
-}
-
-bool ExtensionToolbarModel::RedesignIsShowingNewIcons() const {
- for (const scoped_refptr<const Extension>& extension : toolbar_items_) {
- // Without the redesign, we only show extensions with browser actions.
- // Any extension without a browser action is an indication that we're
- // showing something new.
- if (!extension->manifest()->HasKey(manifest_keys::kBrowserAction))
- return true;
- }
- return false;
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h
deleted file mode 100644
index 2093ac8..0000000
--- a/chrome/browser/extensions/extension_toolbar_model.h
+++ /dev/null
@@ -1,277 +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_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
-
-#include "base/compiler_specific.h"
-#include "base/observer_list.h"
-#include "base/prefs/pref_change_registrar.h"
-#include "base/scoped_observer.h"
-#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/extension_action.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_registry_observer.h"
-#include "extensions/common/extension.h"
-
-class Browser;
-class PrefService;
-class Profile;
-
-namespace extensions {
-class ExtensionRegistry;
-class ExtensionSet;
-
-// Model for the browser actions toolbar.
-class ExtensionToolbarModel : public ExtensionActionAPI::Observer,
- public ExtensionRegistryObserver,
- public KeyedService {
- public:
- // The different options for highlighting.
- enum HighlightType {
- HIGHLIGHT_NONE,
- HIGHLIGHT_INFO,
- HIGHLIGHT_WARNING,
- };
-
- ExtensionToolbarModel(Profile* profile, ExtensionPrefs* extension_prefs);
- ~ExtensionToolbarModel() override;
-
- // A class which is informed of changes to the model; represents the view of
- // MVC. Also used for signaling view changes such as showing extension popups.
- // TODO(devlin): Should this really be an observer? It acts more like a
- // delegate.
- class Observer {
- public:
- // Signals that an |extension| has been added to the toolbar at |index|.
- // This will *only* be called after the toolbar model has been initialized.
- virtual void OnToolbarExtensionAdded(const Extension* extension,
- int index) = 0;
-
- // Signals that the given |extension| has been removed from the toolbar.
- virtual void OnToolbarExtensionRemoved(const Extension* extension) = 0;
-
- // Signals that the given |extension| has been moved to |index|. |index| is
- // the desired *final* index of the extension (that is, in the adjusted
- // order, extension should be at |index|).
- virtual void OnToolbarExtensionMoved(const Extension* extension,
- int index) = 0;
-
- // Signals that the browser action for the given |extension| has been
- // updated.
- virtual void OnToolbarExtensionUpdated(const Extension* extension) = 0;
-
- // Signals the |extension| to show the popup now in the active window.
- // If |grant_active_tab| is true, then active tab permissions should be
- // given to the extension (only do this if this is through a user action).
- // Returns true if a popup was slated to be shown.
- virtual bool ShowExtensionActionPopup(const Extension* extension,
- bool grant_active_tab) = 0;
-
- // Signals when the container needs to be redrawn because of a size change,
- // and when the model has finished loading.
- virtual void OnToolbarVisibleCountChanged() = 0;
-
- // Signals that the model has entered or exited highlighting mode, or that
- // the extensions being highlighted have (probably*) changed. Highlighting
- // mode indicates that only a subset of the extensions are actively
- // displayed, and those extensions should be highlighted for extra emphasis.
- // * probably, because if we are in highlight mode and receive a call to
- // highlight a new set of extensions, we do not compare the current set
- // with the new set (and just assume the new set is different).
- virtual void OnToolbarHighlightModeChanged(bool is_highlighting) = 0;
-
- // Signals that the toolbar model has been initialized, so that if any
- // observers were postponing animation during the initialization stage, they
- // can catch up.
- virtual void OnToolbarModelInitialized() = 0;
-
- // Returns the browser associated with the Observer.
- virtual Browser* GetBrowser() = 0;
-
- protected:
- virtual ~Observer() {}
- };
-
- // Convenience function to get the ExtensionToolbarModel for a Profile.
- static ExtensionToolbarModel* Get(Profile* profile);
-
- // Adds or removes an observer.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- // Moves the given |extension|'s icon to the given |index|.
- void MoveExtensionIcon(const std::string& id, size_t index);
-
- // Sets the number of extension icons that should be visible.
- // If count == size(), this will set the visible icon count to -1, meaning
- // "show all actions".
- void SetVisibleIconCount(size_t count);
-
- size_t visible_icon_count() const {
- // We have guards around this because |visible_icon_count_| can be set by
- // prefs/sync, and we want to ensure that the icon count returned is within
- // bounds.
- return visible_icon_count_ == -1 ?
- toolbar_items().size() :
- std::min(static_cast<size_t>(visible_icon_count_),
- toolbar_items().size());
- }
-
- bool all_icons_visible() const { return visible_icon_count_ == -1; }
-
- bool extensions_initialized() const { return extensions_initialized_; }
-
- const ExtensionList& toolbar_items() const {
- return is_highlighting() ? highlighted_items_ : toolbar_items_;
- }
-
- bool is_highlighting() const { return highlight_type_ != HIGHLIGHT_NONE; }
- HighlightType highlight_type() const { return highlight_type_; }
-
- void OnExtensionToolbarPrefChange();
-
- // Returns the index of the given |id|, or -1 if the id wasn't found.
- int GetIndexForId(const std::string& id) const;
-
- // Finds the Observer associated with |browser| and tells it to display a
- // popup for the given |extension|. If |grant_active_tab| is true, this
- // grants active tab permissions to the |extension|; only do this because of
- // a direct user action.
- bool ShowExtensionActionPopup(const Extension* extension,
- Browser* browser,
- bool grant_active_tab);
-
- // Ensures that the extensions in the |extension_ids| list are visible on the
- // toolbar. This might mean they need to be moved to the front (if they are in
- // the overflow bucket).
- void EnsureVisibility(const ExtensionIdList& extension_ids);
-
- // Highlights the extensions specified by |extension_ids|. This will cause
- // the ToolbarModel to only display those extensions.
- // Highlighting mode is only entered if there is at least one extension to
- // be shown.
- // Returns true if highlighting mode is entered, false otherwise.
- bool HighlightExtensions(const ExtensionIdList& extension_ids,
- HighlightType type);
-
- // Stop highlighting extensions. All extensions can be shown again, and the
- // number of visible icons will be reset to what it was before highlighting.
- void StopHighlighting();
-
- // Returns true if the toolbar model is running with the redesign and is
- // showing new icons as a result.
- bool RedesignIsShowingNewIcons() const;
-
- private:
- // Callback when extensions are ready.
- void OnReady();
-
- // ExtensionRegistryObserver:
- void OnExtensionLoaded(content::BrowserContext* browser_context,
- const Extension* extension) override;
- void OnExtensionUnloaded(content::BrowserContext* browser_context,
- const Extension* extension,
- UnloadedExtensionInfo::Reason reason) override;
- void OnExtensionUninstalled(content::BrowserContext* browser_context,
- const Extension* extension,
- extensions::UninstallReason reason) override;
-
- // ExtensionActionAPI::Observer:
- void OnExtensionActionUpdated(
- ExtensionAction* extension_action,
- content::WebContents* web_contents,
- content::BrowserContext* browser_context) override;
- void OnExtensionActionVisibilityChanged(const std::string& extension_id,
- bool is_now_visible) override;
-
- // To be called after the extension service is ready; gets loaded extensions
- // from the ExtensionRegistry and their saved order from the pref service
- // and constructs |toolbar_items_| from these data. IncognitoPopulate()
- // takes the shortcut - looking at the regular model's content and modifying
- // it.
- void InitializeExtensionList();
- void Populate(ExtensionIdList* positions);
- void IncognitoPopulate();
-
- // Save the model to prefs.
- void UpdatePrefs();
-
- // Updates |extension|'s browser action visibility pref if the browser action
- // is in the overflow menu and should be considered hidden.
- void MaybeUpdateVisibilityPref(const Extension* extension, size_t index);
-
- // Calls MaybeUpdateVisibilityPref() for each extension in |toolbar_items|.
- void MaybeUpdateVisibilityPrefs();
-
- // Finds the last known visible position of the icon for an |extension|. The
- // value returned is a zero-based index into the vector of visible items.
- size_t FindNewPositionFromLastKnownGood(const Extension* extension);
-
- // Returns true if the given |extension| should be added to the toolbar.
- bool ShouldAddExtension(const Extension* extension);
-
- // Adds or removes the given |extension| from the toolbar model.
- void AddExtension(const Extension* extension);
- void RemoveExtension(const Extension* extension);
-
- // Our observers.
- base::ObserverList<Observer> observers_;
-
- // The Profile this toolbar model is for.
- Profile* profile_;
-
- ExtensionPrefs* extension_prefs_;
- PrefService* prefs_;
-
- // The ExtensionActionAPI object, cached for convenience.
- ExtensionActionAPI* extension_action_api_;
-
- // True if we've handled the initial EXTENSIONS_READY notification.
- bool extensions_initialized_;
-
- // If true, we include all extensions in the toolbar model. If false, we only
- // include browser actions.
- bool include_all_extensions_;
-
- // Ordered list of browser action buttons.
- ExtensionList toolbar_items_;
-
- // List of browser action buttons which should be highlighted.
- ExtensionList highlighted_items_;
-
- // The current type of highlight (with HIGHLIGHT_NONE indicating no current
- // highlight).
- HighlightType highlight_type_;
-
- ExtensionIdList last_known_positions_;
-
- // The number of icons visible (the rest should be hidden in the overflow
- // chevron). A value of -1 indicates that all icons should be visible.
- // Instead of using this variable directly, use visible_icon_count() if
- // possible.
- // TODO(devlin): Make a new variable to indicate that all icons should be
- // visible, instead of overloading this one.
- int visible_icon_count_;
-
- ScopedObserver<ExtensionActionAPI, ExtensionActionAPI::Observer>
- extension_action_observer_;
-
- // Listen to extension load, unloaded notifications.
- ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
- extension_registry_observer_;
-
- // For observing change of toolbar order preference by external entity (sync).
- PrefChangeRegistrar pref_change_registrar_;
- base::Closure pref_change_callback_;
-
- base::WeakPtrFactory<ExtensionToolbarModel> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionToolbarModel);
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
diff --git a/chrome/browser/extensions/extension_toolbar_model_factory.cc b/chrome/browser/extensions/extension_toolbar_model_factory.cc
deleted file mode 100644
index a51904c..0000000
--- a/chrome/browser/extensions/extension_toolbar_model_factory.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 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/extensions/extension_toolbar_model_factory.h"
-
-#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_prefs_factory.h"
-#include "extensions/browser/extensions_browser_client.h"
-
-namespace extensions {
-
-// static
-ExtensionToolbarModel* ExtensionToolbarModelFactory::GetForProfile(
- Profile* profile) {
- return static_cast<ExtensionToolbarModel*>(
- GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-ExtensionToolbarModelFactory* ExtensionToolbarModelFactory::GetInstance() {
- return Singleton<ExtensionToolbarModelFactory>::get();
-}
-
-ExtensionToolbarModelFactory::ExtensionToolbarModelFactory()
- : BrowserContextKeyedServiceFactory(
- "ExtensionToolbarModel",
- BrowserContextDependencyManager::GetInstance()) {
- DependsOn(ExtensionPrefsFactory::GetInstance());
- DependsOn(ExtensionActionAPI::GetFactoryInstance());
-}
-
-ExtensionToolbarModelFactory::~ExtensionToolbarModelFactory() {}
-
-KeyedService* ExtensionToolbarModelFactory::BuildServiceInstanceFor(
- content::BrowserContext* context) const {
- return new ExtensionToolbarModel(
- Profile::FromBrowserContext(context),
- ExtensionPrefsFactory::GetForBrowserContext(context));
-}
-
-content::BrowserContext* ExtensionToolbarModelFactory::GetBrowserContextToUse(
- content::BrowserContext* context) const {
- return context;
-}
-
-bool ExtensionToolbarModelFactory::ServiceIsCreatedWithBrowserContext() const {
- return true;
-}
-
-bool ExtensionToolbarModelFactory::ServiceIsNULLWhileTesting() const {
- return true;
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/extension_toolbar_model_unittest.cc b/chrome/browser/extensions/extension_toolbar_model_unittest.cc
deleted file mode 100644
index 1d175d7d..0000000
--- a/chrome/browser/extensions/extension_toolbar_model_unittest.cc
+++ /dev/null
@@ -1,1210 +0,0 @@
-// Copyright 2014 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 "base/files/file_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_action_test_util.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_service_test_base.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/test_extension_dir.h"
-#include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/extensions/unpacked_installer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sessions/session_tab_helper.h"
-#include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
-#include "components/crx_file/id_util.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/web_contents_tester.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/pref_names.h"
-#include "extensions/browser/test_extension_registry_observer.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/extension_builder.h"
-#include "extensions/common/feature_switch.h"
-#include "extensions/common/value_builder.h"
-
-namespace extensions {
-
-namespace {
-
-// A simple observer that tracks the number of times certain events occur.
-class ExtensionToolbarModelTestObserver
- : public ExtensionToolbarModel::Observer {
- public:
- explicit ExtensionToolbarModelTestObserver(ExtensionToolbarModel* model);
- ~ExtensionToolbarModelTestObserver() override;
-
- size_t inserted_count() const { return inserted_count_; }
- size_t removed_count() const { return removed_count_; }
- size_t moved_count() const { return moved_count_; }
- int highlight_mode_count() const { return highlight_mode_count_; }
- size_t initialized_count() const { return initialized_count_; }
-
- private:
- // ExtensionToolbarModel::Observer:
- void OnToolbarExtensionAdded(const Extension* extension, int index) override {
- ++inserted_count_;
- }
-
- void OnToolbarExtensionRemoved(const Extension* extension) override {
- ++removed_count_;
- }
-
- void OnToolbarExtensionMoved(const Extension* extension, int index) override {
- ++moved_count_;
- }
-
- void OnToolbarExtensionUpdated(const Extension* extension) override {}
-
- bool ShowExtensionActionPopup(const Extension* extension,
- bool grant_active_tab) override {
- return false;
- }
-
- void OnToolbarVisibleCountChanged() override {}
-
- void OnToolbarHighlightModeChanged(bool is_highlighting) override {
- // Add one if highlighting, subtract one if not.
- highlight_mode_count_ += is_highlighting ? 1 : -1;
- }
-
- void OnToolbarModelInitialized() override { ++initialized_count_; }
-
- Browser* GetBrowser() override { return NULL; }
-
- ExtensionToolbarModel* model_;
-
- size_t inserted_count_;
- size_t removed_count_;
- size_t moved_count_;
- // Int because it could become negative (if something goes wrong).
- int highlight_mode_count_;
- size_t initialized_count_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionToolbarModelTestObserver);
-};
-
-ExtensionToolbarModelTestObserver::ExtensionToolbarModelTestObserver(
- ExtensionToolbarModel* model) : model_(model),
- inserted_count_(0),
- removed_count_(0),
- moved_count_(0),
- highlight_mode_count_(0),
- initialized_count_(0) {
- model_->AddObserver(this);
-}
-
-ExtensionToolbarModelTestObserver::~ExtensionToolbarModelTestObserver() {
- model_->RemoveObserver(this);
-}
-
-} // namespace
-
-class ExtensionToolbarModelUnitTest : public ExtensionServiceTestBase {
- protected:
- // Initialize the ExtensionService, ExtensionToolbarModel, and
- // ExtensionSystem.
- void Init();
-
- void TearDown() override;
-
- // Adds or removes the given |extension| and verify success.
- testing::AssertionResult AddExtension(
- const scoped_refptr<const Extension>& extension) WARN_UNUSED_RESULT;
- testing::AssertionResult RemoveExtension(
- const scoped_refptr<const Extension>& extension) WARN_UNUSED_RESULT;
-
- // Adds three extensions, all with browser actions.
- testing::AssertionResult AddBrowserActionExtensions() WARN_UNUSED_RESULT;
-
- // Adds three extensions, one each for browser action, page action, and no
- // action, and are added in that order.
- testing::AssertionResult AddActionExtensions() WARN_UNUSED_RESULT;
-
- // Returns the extension at the given index in the toolbar model, or NULL
- // if one does not exist.
- // If |model| is specified, it is used. Otherwise, this defaults to
- // |toolbar_model_|.
- const Extension* GetExtensionAtIndex(
- size_t index, const ExtensionToolbarModel* model) const;
- const Extension* GetExtensionAtIndex(size_t index) const;
-
- ExtensionToolbarModel* toolbar_model() { return toolbar_model_; }
-
- const ExtensionToolbarModelTestObserver* observer() const {
- return model_observer_.get();
- }
- size_t num_toolbar_items() const {
- return toolbar_model_->toolbar_items().size();
- }
- const Extension* browser_action_a() const { return browser_action_a_.get(); }
- const Extension* browser_action_b() const { return browser_action_b_.get(); }
- const Extension* browser_action_c() const { return browser_action_c_.get(); }
- const Extension* browser_action() const {
- return browser_action_extension_.get();
- }
- const Extension* page_action() const { return page_action_extension_.get(); }
- const Extension* no_action() const { return no_action_extension_.get(); }
-
- private:
- // Verifies that all extensions in |extensions| are added successfully.
- testing::AssertionResult AddAndVerifyExtensions(
- const ExtensionList& extensions);
-
- // The toolbar model associated with the testing profile.
- ExtensionToolbarModel* toolbar_model_;
-
- // The test observer to track events. Must come after toolbar_model_ so that
- // it is destroyed and removes itself as an observer first.
- scoped_ptr<ExtensionToolbarModelTestObserver> model_observer_;
-
- // Sample extensions with only browser actions.
- scoped_refptr<const Extension> browser_action_a_;
- scoped_refptr<const Extension> browser_action_b_;
- scoped_refptr<const Extension> browser_action_c_;
-
- // Sample extensions with different kinds of actions.
- scoped_refptr<const Extension> browser_action_extension_;
- scoped_refptr<const Extension> page_action_extension_;
- scoped_refptr<const Extension> no_action_extension_;
-};
-
-void ExtensionToolbarModelUnitTest::Init() {
- InitializeEmptyExtensionService();
- toolbar_model_ =
- extension_action_test_util::CreateToolbarModelForProfile(profile());
- model_observer_.reset(new ExtensionToolbarModelTestObserver(toolbar_model_));
-}
-
-void ExtensionToolbarModelUnitTest::TearDown() {
- model_observer_.reset();
- ExtensionServiceTestBase::TearDown();
-}
-
-testing::AssertionResult ExtensionToolbarModelUnitTest::AddExtension(
- const scoped_refptr<const Extension>& extension) {
- if (registry()->enabled_extensions().GetByID(extension->id())) {
- return testing::AssertionFailure() << "Extension " << extension->name() <<
- " already installed!";
- }
- service()->AddExtension(extension.get());
- if (!registry()->enabled_extensions().GetByID(extension->id())) {
- return testing::AssertionFailure() << "Failed to install extension: " <<
- extension->name();
- }
- return testing::AssertionSuccess();
-}
-
-testing::AssertionResult ExtensionToolbarModelUnitTest::RemoveExtension(
- const scoped_refptr<const Extension>& extension) {
- if (!registry()->enabled_extensions().GetByID(extension->id())) {
- return testing::AssertionFailure() << "Extension " << extension->name() <<
- " not installed!";
- }
- service()->UnloadExtension(extension->id(),
- UnloadedExtensionInfo::REASON_DISABLE);
- if (registry()->enabled_extensions().GetByID(extension->id())) {
- return testing::AssertionFailure() << "Failed to unload extension: " <<
- extension->name();
- }
- return testing::AssertionSuccess();
-}
-
-testing::AssertionResult ExtensionToolbarModelUnitTest::AddActionExtensions() {
- browser_action_extension_ = extension_action_test_util::CreateActionExtension(
- "browser_action", extension_action_test_util::BROWSER_ACTION);
- page_action_extension_ = extension_action_test_util::CreateActionExtension(
- "page_action", extension_action_test_util::PAGE_ACTION);
- no_action_extension_ = extension_action_test_util::CreateActionExtension(
- "no_action", extension_action_test_util::NO_ACTION);
-
- ExtensionList extensions;
- extensions.push_back(browser_action_extension_);
- extensions.push_back(page_action_extension_);
- extensions.push_back(no_action_extension_);
-
- return AddAndVerifyExtensions(extensions);
-}
-
-testing::AssertionResult
-ExtensionToolbarModelUnitTest::AddBrowserActionExtensions() {
- browser_action_a_ = extension_action_test_util::CreateActionExtension(
- "browser_actionA", extension_action_test_util::BROWSER_ACTION);
- browser_action_b_ = extension_action_test_util::CreateActionExtension(
- "browser_actionB", extension_action_test_util::BROWSER_ACTION);
- browser_action_c_ = extension_action_test_util::CreateActionExtension(
- "browser_actionC", extension_action_test_util::BROWSER_ACTION);
-
- ExtensionList extensions;
- extensions.push_back(browser_action_a_);
- extensions.push_back(browser_action_b_);
- extensions.push_back(browser_action_c_);
-
- return AddAndVerifyExtensions(extensions);
-}
-
-const Extension* ExtensionToolbarModelUnitTest::GetExtensionAtIndex(
- size_t index, const ExtensionToolbarModel* model) const {
- return index < model->toolbar_items().size()
- ? model->toolbar_items()[index].get()
- : NULL;
-}
-
-const Extension* ExtensionToolbarModelUnitTest::GetExtensionAtIndex(
- size_t index) const {
- return GetExtensionAtIndex(index, toolbar_model_);
-}
-
-testing::AssertionResult ExtensionToolbarModelUnitTest::AddAndVerifyExtensions(
- const ExtensionList& extensions) {
- for (ExtensionList::const_iterator iter = extensions.begin();
- iter != extensions.end(); ++iter) {
- if (!AddExtension(*iter)) {
- return testing::AssertionFailure() << "Failed to install extension: " <<
- (*iter)->name();
- }
- }
- return testing::AssertionSuccess();
-}
-
-// A basic test for extensions with browser actions showing up in the toolbar.
-TEST_F(ExtensionToolbarModelUnitTest, BasicExtensionToolbarModelTest) {
- Init();
-
- // Load an extension with no browser action.
- scoped_refptr<const Extension> extension1 =
- extension_action_test_util::CreateActionExtension(
- "no_action", extension_action_test_util::NO_ACTION);
- ASSERT_TRUE(AddExtension(extension1));
-
- // This extension should not be in the model (has no browser action).
- EXPECT_EQ(0u, observer()->inserted_count());
- EXPECT_EQ(0u, num_toolbar_items());
- EXPECT_EQ(NULL, GetExtensionAtIndex(0u));
-
- // Load an extension with a browser action.
- scoped_refptr<const Extension> extension2 =
- extension_action_test_util::CreateActionExtension(
- "browser_action", extension_action_test_util::BROWSER_ACTION);
- ASSERT_TRUE(AddExtension(extension2));
-
- // We should now find our extension in the model.
- EXPECT_EQ(1u, observer()->inserted_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(extension2.get(), GetExtensionAtIndex(0u));
-
- // Should be a no-op, but still fires the events.
- toolbar_model()->MoveExtensionIcon(extension2->id(), 0);
- EXPECT_EQ(1u, observer()->moved_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(extension2.get(), GetExtensionAtIndex(0u));
-
- // Remove the extension and verify.
- ASSERT_TRUE(RemoveExtension(extension2));
- EXPECT_EQ(1u, observer()->removed_count());
- EXPECT_EQ(0u, num_toolbar_items());
- EXPECT_EQ(NULL, GetExtensionAtIndex(0u));
-}
-
-// Test various different reorderings, removals, and reinsertions.
-TEST_F(ExtensionToolbarModelUnitTest, ExtensionToolbarReorderAndReinsert) {
- Init();
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
-
- // Verify the three extensions are in the model in the proper order.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-
- // Order is now A, B, C. Let's put C first.
- toolbar_model()->MoveExtensionIcon(browser_action_c()->id(), 0);
- EXPECT_EQ(1u, observer()->moved_count());
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(2u));
-
- // Order is now C, A, B. Let's put A last.
- toolbar_model()->MoveExtensionIcon(browser_action_a()->id(), 2);
- EXPECT_EQ(2u, observer()->moved_count());
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(2u));
-
- // Order is now C, B, A. Let's remove B.
- ASSERT_TRUE(RemoveExtension(browser_action_b()));
- EXPECT_EQ(1u, observer()->removed_count());
- EXPECT_EQ(2u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(1u));
-
- // Load extension B again.
- ASSERT_TRUE(AddExtension(browser_action_b()));
-
- // Extension B loaded again.
- EXPECT_EQ(4u, observer()->inserted_count());
- EXPECT_EQ(3u, num_toolbar_items());
- // Make sure it gets its old spot in the list.
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
-
- // Unload B again.
- ASSERT_TRUE(RemoveExtension(browser_action_b()));
- EXPECT_EQ(2u, observer()->removed_count());
- EXPECT_EQ(2u, num_toolbar_items());
-
- // Order is now C, A. Flip it.
- toolbar_model()->MoveExtensionIcon(browser_action_a()->id(), 0);
- EXPECT_EQ(3u, observer()->moved_count());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
-
- // Move A to the location it already occupies.
- toolbar_model()->MoveExtensionIcon(browser_action_a()->id(), 0);
- EXPECT_EQ(4u, observer()->moved_count());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
-
- // Order is now A, C. Remove C.
- ASSERT_TRUE(RemoveExtension(browser_action_c()));
- EXPECT_EQ(3u, observer()->removed_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
-
- // Load extension C again.
- ASSERT_TRUE(AddExtension(browser_action_c()));
-
- // Extension C loaded again.
- EXPECT_EQ(5u, observer()->inserted_count());
- EXPECT_EQ(2u, num_toolbar_items());
- // Make sure it gets its old spot in the list (at the very end).
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
-}
-
-// Test that order persists after unloading and disabling, but not across
-// uninstallation.
-TEST_F(ExtensionToolbarModelUnitTest,
- ExtensionToolbarUnloadDisableAndUninstall) {
- Init();
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
-
- // Verify the three extensions are in the model in the proper order: A, B, C.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-
- // Unload B, then C, then A, and then reload C, then A, then B.
- ASSERT_TRUE(RemoveExtension(browser_action_b()));
- ASSERT_TRUE(RemoveExtension(browser_action_c()));
- ASSERT_TRUE(RemoveExtension(browser_action_a()));
- EXPECT_EQ(0u, num_toolbar_items()); // Sanity check: all gone?
- ASSERT_TRUE(AddExtension(browser_action_c()));
- ASSERT_TRUE(AddExtension(browser_action_a()));
- ASSERT_TRUE(AddExtension(browser_action_b()));
- EXPECT_EQ(3u, num_toolbar_items()); // Sanity check: all back?
- EXPECT_EQ(0u, observer()->moved_count());
-
- // Even though we unloaded and reloaded in a different order, the original
- // order (A, B, C) should be preserved.
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-
- // Disabling extensions should also preserve order.
- service()->DisableExtension(browser_action_b()->id(),
- Extension::DISABLE_USER_ACTION);
- service()->DisableExtension(browser_action_c()->id(),
- Extension::DISABLE_USER_ACTION);
- service()->DisableExtension(browser_action_a()->id(),
- Extension::DISABLE_USER_ACTION);
- service()->EnableExtension(browser_action_c()->id());
- service()->EnableExtension(browser_action_a()->id());
- service()->EnableExtension(browser_action_b()->id());
-
- // Make sure we still get the original A, B, C order.
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-
- // Move browser_action_b() to be first.
- toolbar_model()->MoveExtensionIcon(browser_action_b()->id(), 0);
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(0u));
-
- // Uninstall Extension B.
- service()->UninstallExtension(browser_action_b()->id(),
- UNINSTALL_REASON_FOR_TESTING,
- base::Bind(&base::DoNothing),
- NULL); // Ignore error.
- // List contains only A and C now. Validate that.
- EXPECT_EQ(2u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
-
- ASSERT_TRUE(AddExtension(browser_action_b()));
-
- // Make sure Extension B is _not_ first (its old position should have been
- // forgotten at uninstall time). Order should be A, C, B.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(2u));
-}
-
-TEST_F(ExtensionToolbarModelUnitTest, ReorderOnPrefChange) {
- Init();
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
- EXPECT_EQ(3u, num_toolbar_items());
-
- // Change the value of the toolbar preference.
- ExtensionIdList new_order;
- new_order.push_back(browser_action_c()->id());
- new_order.push_back(browser_action_b()->id());
- ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order);
-
- // Verify order is changed.
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(2u));
-}
-
-// Test that new extensions are always visible on installation and inserted at
-// the "end" of the visible section.
-TEST_F(ExtensionToolbarModelUnitTest, NewToolbarExtensionsAreVisible) {
- Init();
-
- // Three extensions with actions.
- scoped_refptr<const Extension> extension_a =
- extension_action_test_util::CreateActionExtension(
- "a", extension_action_test_util::BROWSER_ACTION);
- scoped_refptr<const Extension> extension_b =
- extension_action_test_util::CreateActionExtension(
- "b", extension_action_test_util::BROWSER_ACTION);
- scoped_refptr<const Extension> extension_c =
- extension_action_test_util::CreateActionExtension(
- "c", extension_action_test_util::BROWSER_ACTION);
- scoped_refptr<const Extension> extension_d =
- extension_action_test_util::CreateActionExtension(
- "d", extension_action_test_util::BROWSER_ACTION);
-
- // We should start off without any extensions.
- EXPECT_EQ(0u, num_toolbar_items());
- EXPECT_EQ(0u, toolbar_model()->visible_icon_count());
-
- // Add one extension. It should be visible.
- service()->AddExtension(extension_a.get());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(extension_a.get(), GetExtensionAtIndex(0u));
-
- // Hide all extensions.
- toolbar_model()->SetVisibleIconCount(0);
- EXPECT_EQ(0u, toolbar_model()->visible_icon_count());
-
- // Add a new extension - it should be visible, so it should be in the first
- // index. The other extension should remain hidden.
- service()->AddExtension(extension_b.get());
- EXPECT_EQ(2u, num_toolbar_items());
- EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(extension_b.get(), GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_a.get(), GetExtensionAtIndex(1u));
-
- // Show all extensions.
- toolbar_model()->SetVisibleIconCount(2);
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
- EXPECT_TRUE(toolbar_model()->all_icons_visible());
-
- // Add the third extension. Since all extensions are visible, it should go in
- // the last index.
- service()->AddExtension(extension_c.get());
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
- EXPECT_TRUE(toolbar_model()->all_icons_visible());
- EXPECT_EQ(extension_b.get(), GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_a.get(), GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_c.get(), GetExtensionAtIndex(2u));
-
- // Hide one extension (two remaining visible).
- toolbar_model()->SetVisibleIconCount(2);
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
-
- // Add a fourth extension. It should go at the end of the visible section and
- // be visible, so it increases visible count by 1, and goes into the third
- // index. The hidden extension should remain hidden.
- service()->AddExtension(extension_d.get());
- EXPECT_EQ(4u, num_toolbar_items());
- EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(extension_b.get(), GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_a.get(), GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_d.get(), GetExtensionAtIndex(2u));
- EXPECT_EQ(extension_c.get(), GetExtensionAtIndex(3u));
-}
-
-TEST_F(ExtensionToolbarModelUnitTest, ExtensionToolbarHighlightMode) {
- Init();
-
- EXPECT_FALSE(toolbar_model()->HighlightExtensions(
- ExtensionIdList(), ExtensionToolbarModel::HIGHLIGHT_WARNING));
- EXPECT_EQ(0, observer()->highlight_mode_count());
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
- EXPECT_EQ(3u, num_toolbar_items());
-
- // Start with a visible count of 2 (non-zero, and not all).
- toolbar_model()->SetVisibleIconCount(2u);
-
- // Highlight one extension.
- ExtensionIdList extension_ids;
- extension_ids.push_back(browser_action_b()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_EQ(1, observer()->highlight_mode_count());
- EXPECT_TRUE(toolbar_model()->is_highlighting());
-
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(0u));
- EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
-
- // Stop highlighting.
- toolbar_model()->StopHighlighting();
- EXPECT_EQ(0, observer()->highlight_mode_count());
- EXPECT_FALSE(toolbar_model()->is_highlighting());
-
- // Verify that the extensions are back to normal.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
-
- // Call stop highlighting a second time (shouldn't be notified).
- toolbar_model()->StopHighlighting();
- EXPECT_EQ(0, observer()->highlight_mode_count());
- EXPECT_FALSE(toolbar_model()->is_highlighting());
-
- // Highlight all extensions.
- extension_ids.clear();
- extension_ids.push_back(browser_action_a()->id());
- extension_ids.push_back(browser_action_b()->id());
- extension_ids.push_back(browser_action_c()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_EQ(1, observer()->highlight_mode_count());
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
- EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
- // Even though the visible count is 3, we shouldn't adjust the stored
- // preference.
- EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(pref_names::kToolbarSize));
-
- // Highlight only extension b (shrink the highlight list).
- extension_ids.clear();
- extension_ids.push_back(browser_action_b()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_EQ(2, observer()->highlight_mode_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(0u));
-
- // Highlight extensions a and b (grow the highlight list).
- extension_ids.clear();
- extension_ids.push_back(browser_action_a()->id());
- extension_ids.push_back(browser_action_b()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_EQ(3, observer()->highlight_mode_count());
- EXPECT_EQ(2u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
-
- // Highlight no extensions (empty the highlight list).
- extension_ids.clear();
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_EQ(2, observer()->highlight_mode_count());
- EXPECT_FALSE(toolbar_model()->is_highlighting());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-
- // Our toolbar size should be back to normal.
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(pref_names::kToolbarSize));
-}
-
-TEST_F(ExtensionToolbarModelUnitTest, ExtensionToolbarHighlightModeRemove) {
- Init();
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
- EXPECT_EQ(3u, num_toolbar_items());
-
- // Highlight two of the extensions.
- ExtensionIdList extension_ids;
- extension_ids.push_back(browser_action_a()->id());
- extension_ids.push_back(browser_action_b()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_TRUE(toolbar_model()->is_highlighting());
- EXPECT_EQ(1, observer()->highlight_mode_count());
- EXPECT_EQ(2u, num_toolbar_items());
-
- // Disable one of them - only one should remain highlighted.
- service()->DisableExtension(browser_action_a()->id(),
- Extension::DISABLE_USER_ACTION);
- EXPECT_TRUE(toolbar_model()->is_highlighting());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(0u));
-
- // Uninstall the remaining highlighted extension. This should result in
- // highlight mode exiting.
- service()->UninstallExtension(browser_action_b()->id(),
- UNINSTALL_REASON_FOR_TESTING,
- base::Bind(&base::DoNothing),
- NULL); // Ignore error.
- EXPECT_FALSE(toolbar_model()->is_highlighting());
- EXPECT_EQ(0, observer()->highlight_mode_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
-
- // Test that removing an unhighlighted extension still works.
- // Reinstall extension b, and then highlight extension c.
- ASSERT_TRUE(AddExtension(browser_action_b()));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- extension_ids.clear();
- extension_ids.push_back(browser_action_c()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_EQ(1, observer()->highlight_mode_count());
- EXPECT_TRUE(toolbar_model()->is_highlighting());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
-
- // Uninstalling b should not have visible impact.
- service()->UninstallExtension(browser_action_b()->id(),
- UNINSTALL_REASON_FOR_TESTING,
- base::Bind(&base::DoNothing),
- NULL); // Ignore error.
- EXPECT_TRUE(toolbar_model()->is_highlighting());
- EXPECT_EQ(1, observer()->highlight_mode_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
-
- // When we stop, only extension c should remain.
- toolbar_model()->StopHighlighting();
- EXPECT_FALSE(toolbar_model()->is_highlighting());
- EXPECT_EQ(0, observer()->highlight_mode_count());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u));
-}
-
-TEST_F(ExtensionToolbarModelUnitTest, ExtensionToolbarHighlightModeAdd) {
- Init();
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
- EXPECT_EQ(3u, num_toolbar_items());
-
- // Remove one (down to two).
- ASSERT_TRUE(RemoveExtension(browser_action_c()));
-
- // Highlight one of the two extensions.
- ExtensionIdList extension_ids;
- extension_ids.push_back(browser_action_a()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, ExtensionToolbarModel::HIGHLIGHT_WARNING);
- EXPECT_TRUE(toolbar_model()->is_highlighting());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
-
- // Adding a new extension should have no visible effect.
- ASSERT_TRUE(AddExtension(browser_action_c()));
- EXPECT_TRUE(toolbar_model()->is_highlighting());
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
-
- // When we stop highlighting, we should see the new extension show up.
- toolbar_model()->StopHighlighting();
- EXPECT_FALSE(toolbar_model()->is_highlighting());
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-}
-
-// Test that the extension toolbar maintains the proper size, even after a pref
-// change.
-TEST_F(ExtensionToolbarModelUnitTest, ExtensionToolbarSizeAfterPrefChange) {
- Init();
-
- // Add the three browser action extensions.
- ASSERT_TRUE(AddBrowserActionExtensions());
- EXPECT_EQ(3u, num_toolbar_items());
-
- // Should be at max size.
- EXPECT_TRUE(toolbar_model()->all_icons_visible());
- EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count());
- toolbar_model()->OnExtensionToolbarPrefChange();
- // Should still be at max size.
- EXPECT_TRUE(toolbar_model()->all_icons_visible());
- EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count());
-}
-
-// Test that, in the absence of the extension-action-redesign switch, the
-// model only contains extensions with browser actions.
-TEST_F(ExtensionToolbarModelUnitTest, TestToolbarExtensionTypesNoSwitch) {
- Init();
- ASSERT_TRUE(AddActionExtensions());
-
- EXPECT_EQ(1u, num_toolbar_items());
- EXPECT_EQ(browser_action(), GetExtensionAtIndex(0u));
-}
-
-// Test that, with the extension-action-redesign switch, the model contains
-// all types of extensions, except those which should not be displayed on the
-// toolbar (like component extensions).
-TEST_F(ExtensionToolbarModelUnitTest, TestToolbarExtensionTypesSwitch) {
- FeatureSwitch::ScopedOverride enable_redesign(
- FeatureSwitch::extension_action_redesign(), true);
- Init();
- ASSERT_TRUE(AddActionExtensions());
-
- // With the switch on, extensions with page actions and no action should also
- // be displayed in the toolbar.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action(), GetExtensionAtIndex(0u));
- EXPECT_EQ(page_action(), GetExtensionAtIndex(1u));
- EXPECT_EQ(no_action(), GetExtensionAtIndex(2u));
-}
-
-// Test that hiding actions on the toolbar results in their removal from the
-// model when the redesign switch is not enabled.
-TEST_F(ExtensionToolbarModelUnitTest,
- ExtensionToolbarActionsVisibilityNoSwitch) {
- Init();
-
- ExtensionActionAPI* action_api = ExtensionActionAPI::Get(profile());
-
- ASSERT_TRUE(AddBrowserActionExtensions());
- // Sanity check: Order should start as A B C.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-
- // By default, all actions should be visible.
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_a()->id()));
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_b()->id()));
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_c()->id()));
-
- // Hiding an action should result in its removal from the toolbar.
- action_api->SetBrowserActionVisibility(browser_action_b()->id(), false);
- EXPECT_FALSE(action_api->GetBrowserActionVisibility(
- browser_action_b()->id()));
- // Thus, there should now only be two items on the toolbar - A and C.
- EXPECT_EQ(2u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
-
- // Resetting the visibility to 'true' should result in the extension being
- // added back at its original position.
- action_api->SetBrowserActionVisibility(browser_action_b()->id(), true);
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_b()->id()));
- // So the toolbar order should be A B C.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2u));
-}
-
-TEST_F(ExtensionToolbarModelUnitTest, ExtensionToolbarIncognitoModeTest) {
- Init();
- ASSERT_TRUE(AddBrowserActionExtensions());
-
- // Give two extensions incognito access.
- // Note: We use ExtensionPrefs::SetIsIncognitoEnabled instead of
- // util::SetIsIncognitoEnabled because the latter tries to reload the
- // extension, which requries a filepath associated with the extension (and,
- // for this test, reloading the extension is irrelevant to us).
- ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile());
- extension_prefs->SetIsIncognitoEnabled(browser_action_b()->id(), true);
- extension_prefs->SetIsIncognitoEnabled(browser_action_c()->id(), true);
-
- util::SetIsIncognitoEnabled(browser_action_b()->id(), profile(), true);
- util::SetIsIncognitoEnabled(browser_action_c()->id(), profile(), true);
-
- // Move C to the second index.
- toolbar_model()->MoveExtensionIcon(browser_action_c()->id(), 1u);
- // Set visible count to 2 so that c is overflowed. State is A C [B].
- toolbar_model()->SetVisibleIconCount(2);
- EXPECT_EQ(1u, observer()->moved_count());
-
- // Get an incognito profile and toolbar.
- ExtensionToolbarModel* incognito_model =
- extension_action_test_util::CreateToolbarModelForProfile(
- profile()->GetOffTheRecordProfile());
-
- ExtensionToolbarModelTestObserver incognito_observer(incognito_model);
- EXPECT_EQ(0u, incognito_observer.moved_count());
-
- // We should have two items, C and B, and the order should be preserved from
- // the original model.
- EXPECT_EQ(2u, incognito_model->toolbar_items().size());
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(0u, incognito_model));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1u, incognito_model));
-
- // Extensions in the overflow menu in the regular toolbar should remain in
- // overflow in the incognito toolbar. So, we should have C [B].
- EXPECT_EQ(1u, incognito_model->visible_icon_count());
- // The regular model should still have two icons visible.
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
-
- // Changing the incognito model size should not affect the regular model.
- incognito_model->SetVisibleIconCount(0);
- EXPECT_EQ(0u, incognito_model->visible_icon_count());
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
-
- // Expanding the incognito model to 2 should register as "all icons"
- // since it is all of the incognito-enabled extensions.
- incognito_model->SetVisibleIconCount(2u);
- EXPECT_EQ(2u, incognito_model->visible_icon_count());
- EXPECT_TRUE(incognito_model->all_icons_visible());
-
- // Moving icons in the incognito toolbar should not affect the regular
- // toolbar. Incognito currently has C B...
- incognito_model->MoveExtensionIcon(browser_action_b()->id(), 0u);
- // So now it should be B C...
- EXPECT_EQ(1u, incognito_observer.moved_count());
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(0u, incognito_model));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u, incognito_model));
- // ... and the regular toolbar should be unaffected.
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0u));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1u));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(2u));
-
- // Similarly, the observer for the regular model should not have received
- // any updates.
- EXPECT_EQ(1u, observer()->moved_count());
-
- // And performing moves on the regular model should have no effect on the
- // incognito model or its observers.
- toolbar_model()->MoveExtensionIcon(browser_action_c()->id(), 2u);
- EXPECT_EQ(2u, observer()->moved_count());
- EXPECT_EQ(1u, incognito_observer.moved_count());
-}
-
-// Test that enabling extensions incognito with an active incognito profile
-// works.
-TEST_F(ExtensionToolbarModelUnitTest,
- ExtensionToolbarIncognitoEnableExtension) {
- Init();
-
- const char* kManifest =
- "{"
- " \"name\": \"%s\","
- " \"version\": \"1.0\","
- " \"manifest_version\": 2,"
- " \"browser_action\": {}"
- "}";
-
- // For this test, we need to have "real" extension files, because we need to
- // be able to reload them during the incognito process. Since the toolbar
- // needs to be notified of the reload, we need it this time (as opposed to
- // above, where we simply set the prefs before the incognito bar was
- // created.
- TestExtensionDir dir1;
- dir1.WriteManifest(base::StringPrintf(kManifest, "incognito1"));
- TestExtensionDir dir2;
- dir2.WriteManifest(base::StringPrintf(kManifest, "incognito2"));
-
- TestExtensionDir* dirs[] = { &dir1, &dir2 };
- const Extension* extensions[] = { nullptr, nullptr };
- for (size_t i = 0; i < arraysize(dirs); ++i) {
- // The extension id will be calculated from the file path; we need this to
- // wait for the extension to load.
- base::FilePath path_for_id =
- base::MakeAbsoluteFilePath(dirs[i]->unpacked_path());
- std::string id = crx_file::id_util::GenerateIdForPath(path_for_id);
- TestExtensionRegistryObserver observer(registry(), id);
- UnpackedInstaller::Create(service())->Load(dirs[i]->unpacked_path());
- observer.WaitForExtensionLoaded();
- extensions[i] = registry()->enabled_extensions().GetByID(id);
- ASSERT_TRUE(extensions[i]);
- }
-
- // For readability, alias to A and B. Since we'll be reloading these
- // extensions, we also can't rely on pointers.
- std::string extension_a = extensions[0]->id();
- std::string extension_b = extensions[1]->id();
-
- // The first model should have both extensions visible.
- EXPECT_EQ(2u, toolbar_model()->toolbar_items().size());
- EXPECT_EQ(extension_a, GetExtensionAtIndex(0)->id());
- EXPECT_EQ(extension_b, GetExtensionAtIndex(1)->id());
-
- // Set the model to only show one extension, so the order is A [B].
- toolbar_model()->SetVisibleIconCount(1u);
-
- // Get an incognito profile and toolbar.
- ExtensionToolbarModel* incognito_model =
- extension_action_test_util::CreateToolbarModelForProfile(
- profile()->GetOffTheRecordProfile());
- ExtensionToolbarModelTestObserver incognito_observer(incognito_model);
-
- // Right now, no extensions are enabled in incognito mode.
- EXPECT_EQ(0u, incognito_model->toolbar_items().size());
-
- // Set extension b (which is overflowed) to be enabled in incognito. This
- // results in b reloading, so wait for it.
- {
- TestExtensionRegistryObserver observer(registry(), extension_b);
- util::SetIsIncognitoEnabled(extension_b, profile(), true);
- observer.WaitForExtensionLoaded();
- }
-
- // Now, we should have one icon in the incognito bar. But, since B is
- // overflowed in the main bar, it shouldn't be visible.
- EXPECT_EQ(1u, incognito_model->toolbar_items().size());
- EXPECT_EQ(extension_b, GetExtensionAtIndex(0u, incognito_model)->id());
- EXPECT_EQ(0u, incognito_model->visible_icon_count());
-
- // Also enable extension a for incognito (again, wait for the reload).
- {
- TestExtensionRegistryObserver observer(registry(), extension_a);
- util::SetIsIncognitoEnabled(extension_a, profile(), true);
- observer.WaitForExtensionLoaded();
- }
-
- // Now, both extensions should be enabled in incognito mode. In addition, the
- // incognito toolbar should have expanded to show extension a (since it isn't
- // overflowed in the main bar).
- EXPECT_EQ(2u, incognito_model->toolbar_items().size());
- EXPECT_EQ(extension_a, GetExtensionAtIndex(0u, incognito_model)->id());
- EXPECT_EQ(extension_b, GetExtensionAtIndex(1u, incognito_model)->id());
- EXPECT_EQ(1u, incognito_model->visible_icon_count());
-}
-
-// Test that hiding actions on the toolbar results in sending them to the
-// overflow menu when the redesign switch is enabled.
-TEST_F(ExtensionToolbarModelUnitTest,
- ExtensionToolbarActionsVisibilityWithSwitch) {
- FeatureSwitch::ScopedOverride enable_redesign(
- FeatureSwitch::extension_action_redesign(), true);
- Init();
-
- // We choose to use all types of extensions here, since the misnamed
- // BrowserActionVisibility is now for toolbar visibility.
- ASSERT_TRUE(AddActionExtensions());
-
- // For readability, alias extensions A B C.
- const Extension* extension_a = browser_action();
- const Extension* extension_b = page_action();
- const Extension* extension_c = no_action();
-
- // Sanity check: Order should start as A B C, with all three visible.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_TRUE(toolbar_model()->all_icons_visible());
- EXPECT_EQ(extension_a, GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_b, GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_c, GetExtensionAtIndex(2u));
-
- ExtensionActionAPI* action_api = ExtensionActionAPI::Get(profile());
-
- // By default, all actions should be visible.
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_a->id()));
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_c->id()));
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_b->id()));
-
- // Hiding an action should result in it being sent to the overflow menu.
- action_api->SetBrowserActionVisibility(extension_b->id(), false);
-
- // Thus, the order should be A C B, with B in the overflow.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(extension_a, GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_c, GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_b, GetExtensionAtIndex(2u));
-
- // Hiding an extension's action should result in it being sent to the overflow
- // as well, but as the _first_ extension in the overflow.
- action_api->SetBrowserActionVisibility(extension_a->id(), false);
- // Thus, the order should be C A B, with A and B in the overflow.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(extension_c, GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_a, GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_b, GetExtensionAtIndex(2u));
-
- // Resetting A's visibility to true should send it back to the visible icons
- // (and should grow visible icons by 1), but it should be added to the end of
- // the visible icon list (not to its original position).
- action_api->SetBrowserActionVisibility(extension_a->id(), true);
- // So order is C A B, with only B in the overflow.
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
- EXPECT_EQ(extension_c, GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_a, GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_b, GetExtensionAtIndex(2u));
-
- // Resetting B to be visible should make the order C A B, with no overflow.
- action_api->SetBrowserActionVisibility(extension_b->id(), true);
- EXPECT_EQ(3u, num_toolbar_items());
- EXPECT_TRUE(toolbar_model()->all_icons_visible());
- EXPECT_EQ(extension_c, GetExtensionAtIndex(0u));
- EXPECT_EQ(extension_a, GetExtensionAtIndex(1u));
- EXPECT_EQ(extension_b, GetExtensionAtIndex(2u));
-
- // Regression test for crbug.com/515963. Check that an extension's visibility
- // is updated when it is moved out because another extension was removed.
- toolbar_model()->SetVisibleIconCount(1);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(action_api->GetBrowserActionVisibility(extension_a->id()));
- service()->DisableExtension(extension_c->id(),
- Extension::DISABLE_USER_ACTION);
- EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
- EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_a->id()));
-}
-
-// Test that observers receive no Added notifications until after the
-// ExtensionSystem has initialized.
-TEST_F(ExtensionToolbarModelUnitTest, ModelWaitsForExtensionSystemReady) {
- InitializeEmptyExtensionService();
- ExtensionToolbarModel* toolbar_model =
- extension_action_test_util::
- CreateToolbarModelForProfileWithoutWaitingForReady(profile());
- ExtensionToolbarModelTestObserver model_observer(toolbar_model);
- EXPECT_TRUE(AddBrowserActionExtensions());
-
- // Since the model hasn't been initialized (the ExtensionSystem::ready task
- // hasn't been run), there should be no insertion notifications.
- EXPECT_EQ(0u, model_observer.inserted_count());
- EXPECT_EQ(0u, model_observer.initialized_count());
- EXPECT_FALSE(toolbar_model->extensions_initialized());
-
- // Run the ready task.
- static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile()))->
- SetReady();
- // Run tasks posted to TestExtensionSystem.
- base::RunLoop().RunUntilIdle();
-
- // We should still have no insertions, but should have an initialized count.
- EXPECT_TRUE(toolbar_model->extensions_initialized());
- EXPECT_EQ(0u, model_observer.inserted_count());
- EXPECT_EQ(1u, model_observer.initialized_count());
-}
-
-// Check that the toolbar model correctly clears and reorders when it detects
-// a preference change.
-TEST_F(ExtensionToolbarModelUnitTest, ToolbarModelPrefChange) {
- Init();
-
- ASSERT_TRUE(AddBrowserActionExtensions());
-
- // We should start in the basic A B C order.
- ASSERT_TRUE(browser_action_a());
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2));
- // Record the difference between the inserted and removed counts. The actual
- // value of the counts is not important, but we need to be sure that if we
- // call to remove any, we also add them back.
- size_t inserted_and_removed_difference =
- observer()->inserted_count() - observer()->removed_count();
-
- // Assign a new order, B C A, and write it in the prefs.
- ExtensionIdList new_order;
- new_order.push_back(browser_action_b()->id());
- new_order.push_back(browser_action_c()->id());
- new_order.push_back(browser_action_a()->id());
- ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order);
-
- // Ensure everything has time to run.
- base::RunLoop().RunUntilIdle();
-
- // The new order should be reflected in the model.
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(0));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(1));
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(2));
- EXPECT_EQ(inserted_and_removed_difference,
- observer()->inserted_count() - observer()->removed_count());
-}
-
-TEST_F(ExtensionToolbarModelUnitTest, ComponentExtesionsAddedToEnd) {
- Init();
-
- ASSERT_TRUE(AddBrowserActionExtensions());
-
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(0));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(1));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(2));
-
- const char kName[] = "component";
- DictionaryBuilder manifest;
- manifest.Set("name", kName)
- .Set("description", "An extension")
- .Set("manifest_version", 2)
- .Set("version", "1.0.0")
- .Set("browser_action", DictionaryBuilder().Pass());
- scoped_refptr<const Extension> component_extension =
- ExtensionBuilder().SetManifest(manifest.Pass())
- .SetID(crx_file::id_util::GenerateId(kName))
- .SetLocation(Manifest::COMPONENT)
- .Build();
- service()->AddExtension(component_extension.get());
-
- EXPECT_EQ(component_extension.get(), GetExtensionAtIndex(0));
- EXPECT_EQ(browser_action_a(), GetExtensionAtIndex(1));
- EXPECT_EQ(browser_action_b(), GetExtensionAtIndex(2));
- EXPECT_EQ(browser_action_c(), GetExtensionAtIndex(3));
-}
-
-TEST_F(ExtensionToolbarModelUnitTest,
- ToolbarModelHighlightsForToolbarRedesign) {
- FeatureSwitch::ScopedOverride enable_redesign(
- FeatureSwitch::extension_action_redesign(), true);
- InitializeEmptyExtensionService();
- EXPECT_TRUE(AddActionExtensions());
- ExtensionToolbarModel* toolbar_model =
- extension_action_test_util::CreateToolbarModelForProfile(profile());
- EXPECT_TRUE(toolbar_model);
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
- profile()));
- EXPECT_TRUE(toolbar_model->is_highlighting());
- EXPECT_EQ(ExtensionToolbarModel::HIGHLIGHT_INFO,
- toolbar_model->highlight_type());
- EXPECT_EQ(3u, toolbar_model->visible_icon_count());
- EXPECT_EQ(3u, toolbar_model->toolbar_items().size());
-
- scoped_ptr<ToolbarActionsBarBubbleDelegate> bubble(
- new ExtensionToolbarIconSurfacingBubbleDelegate(profile()));
- bubble->OnBubbleClosed(ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS);
-
- EXPECT_FALSE(toolbar_model->is_highlighting());
- EXPECT_EQ(ExtensionToolbarModel::HIGHLIGHT_NONE,
- toolbar_model->highlight_type());
-}
-
-} // namespace extensions
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
index cee2e9d..c50a6a3 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
@@ -10,7 +10,6 @@
#include "chrome/browser/extensions/extension_action_test_util.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
@@ -22,6 +21,7 @@
#include "chrome/browser/ui/global_error/global_error_service.h"
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "extensions/common/feature_switch.h"
#import "ui/events/test/cocoa_test_event_utils.h"
@@ -137,7 +137,7 @@ class BrowserActionButtonUiTest : public ExtensionBrowserTest {
toolbarController];
ASSERT_TRUE(toolbarController_);
wrenchMenuController_ = [toolbarController_ wrenchMenuController];
- model_ = extensions::ExtensionToolbarModel::Get(profile());
+ model_ = ToolbarActionsModel::Get(profile());
}
void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -155,7 +155,7 @@ class BrowserActionButtonUiTest : public ExtensionBrowserTest {
ToolbarController* toolbarController() { return toolbarController_; }
WrenchMenuController* wrenchMenuController() { return wrenchMenuController_; }
- extensions::ExtensionToolbarModel* model() { return model_; }
+ ToolbarActionsModel* model() { return model_; }
NSView* wrenchButton() { return [toolbarController_ wrenchButton]; }
private:
@@ -163,7 +163,7 @@ class BrowserActionButtonUiTest : public ExtensionBrowserTest {
ToolbarController* toolbarController_ = nil;
WrenchMenuController* wrenchMenuController_ = nil;
- extensions::ExtensionToolbarModel* model_ = nullptr;
+ ToolbarActionsModel* model_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(BrowserActionButtonUiTest);
};
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index 3130239..ad62cb0 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -563,7 +563,7 @@ void ToolbarActionsBarBridge::ShowExtensionMessageBubble(
scoped_ptr<ui::NinePartImageIds> highlight;
if (toolbarActionsBar_->is_highlighting()) {
if (toolbarActionsBar_->highlight_type() ==
- extensions::ExtensionToolbarModel::HIGHLIGHT_INFO)
+ ToolbarActionsModel::HIGHLIGHT_INFO)
highlight.reset(
new ui::NinePartImageIds(IMAGE_GRID(IDR_TOOLBAR_ACTION_HIGHLIGHT)));
else
diff --git a/chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.cc b/chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.cc
index 63763c3..d355351 100644
--- a/chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.cc
+++ b/chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.cc
@@ -7,8 +7,8 @@
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/time/time.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/common/pref_names.h"
#include "extensions/common/feature_switch.h"
#include "grit/chromium_strings.h"
@@ -54,8 +54,7 @@ bool ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
return false;
}
- if (!extensions::ExtensionToolbarModel::Get(profile)->
- RedesignIsShowingNewIcons()) {
+ if (!ToolbarActionsModel::Get(profile)->RedesignIsShowingNewIcons()) {
// We only show the bubble if there are any new icons present - otherwise,
// the user won't see anything different, so we treat it as acknowledged.
AcknowledgeInPrefs(prefs);
@@ -103,5 +102,5 @@ void ExtensionToolbarIconSurfacingBubbleDelegate::OnBubbleClosed(
CloseAction action) {
if (action == CLOSE_EXECUTE)
AcknowledgeInPrefs(profile_->GetPrefs());
- extensions::ExtensionToolbarModel::Get(profile_)->StopHighlighting();
+ ToolbarActionsModel::Get(profile_)->StopHighlighting();
}
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
index a47a3c8..5860926 100644
--- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
+++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -12,12 +12,12 @@
#include "chrome/browser/extensions/extension_action_test_util.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/extensions/extension_action_view_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "components/crx_file/id_util.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
@@ -67,7 +67,7 @@ void BrowserActionsBarBrowserTest::SetUpCommandLine(
void BrowserActionsBarBrowserTest::SetUpOnMainThread() {
ExtensionBrowserTest::SetUpOnMainThread();
browser_actions_bar_.reset(new BrowserActionTestUtil(browser()));
- toolbar_model_ = extensions::ExtensionToolbarModel::Get(profile());
+ toolbar_model_ = ToolbarActionsModel::Get(profile());
}
void BrowserActionsBarBrowserTest::TearDownOnMainThread() {
@@ -147,19 +147,19 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, MoveBrowserActions) {
EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
// Move C to first position. Order is C A B.
- toolbar_model()->MoveExtensionIcon(extension_c()->id(), 0);
+ toolbar_model()->MoveActionIcon(extension_c()->id(), 0);
EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(0));
EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(1));
EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(2));
// Move B to third position. Order is still C A B.
- toolbar_model()->MoveExtensionIcon(extension_b()->id(), 2);
+ toolbar_model()->MoveActionIcon(extension_b()->id(), 2);
EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(0));
EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(1));
EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(2));
// Move B to middle position. Order is C B A.
- toolbar_model()->MoveExtensionIcon(extension_b()->id(), 1);
+ toolbar_model()->MoveActionIcon(extension_b()->id(), 1);
EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(0));
EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(1));
EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(2));
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h
index 58baa28..3dcf83c 100644
--- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h
+++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h
@@ -13,10 +13,10 @@
namespace extensions {
class Extension;
-class ExtensionToolbarModel;
}
class BrowserActionTestUtil;
+class ToolbarActionsModel;
// A platform-independent browser test class for the browser actions bar.
class BrowserActionsBarBrowserTest : public ExtensionBrowserTest {
@@ -31,7 +31,7 @@ class BrowserActionsBarBrowserTest : public ExtensionBrowserTest {
BrowserActionTestUtil* browser_actions_bar() {
return browser_actions_bar_.get();
}
- extensions::ExtensionToolbarModel* toolbar_model() { return toolbar_model_; }
+ ToolbarActionsModel* toolbar_model() { return toolbar_model_; }
// Creates three different extensions, each with a browser action, and adds
// them to associated ExtensionService. These can then be accessed via
@@ -52,7 +52,7 @@ class BrowserActionsBarBrowserTest : public ExtensionBrowserTest {
scoped_ptr<BrowserActionTestUtil> browser_actions_bar_;
// The associated toolbar model, weak.
- extensions::ExtensionToolbarModel* toolbar_model_;
+ ToolbarActionsModel* toolbar_model_;
// Extensions with browser actions used for testing.
scoped_refptr<const extensions::Extension> extension_a_;
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
index bd12ffc..51d882b 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
@@ -7,64 +7,13 @@
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
+#include "chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h"
#include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "extensions/common/feature_switch.h"
-namespace {
-
-const char kMockId[] = "mock_action";
-
-class MockComponentToolbarActionsFactory
- : public ComponentToolbarActionsFactory {
- public:
- explicit MockComponentToolbarActionsFactory(Browser* browser);
- virtual ~MockComponentToolbarActionsFactory();
-
- // ComponentToolbarActionsFactory:
- ScopedVector<ToolbarActionViewController>
- GetComponentToolbarActions(Browser* browser) override;
-
- const std::vector<std::string> action_ids() const {
- return action_ids_;
- }
-
- private:
- // A set of all action ids of created actions.
- std::vector<std::string> action_ids_;
-
- DISALLOW_COPY_AND_ASSIGN(MockComponentToolbarActionsFactory);
-};
-
-MockComponentToolbarActionsFactory::MockComponentToolbarActionsFactory(
- Browser* browser) {
- ComponentToolbarActionsFactory::SetTestingFactory(this);
-
- ScopedVector<ToolbarActionViewController> actions =
- GetComponentToolbarActions(browser);
- for (auto it = actions.begin(); it != actions.end(); ++it) {
- action_ids_.push_back((*it)->GetId());
- }
-}
-
-MockComponentToolbarActionsFactory::~MockComponentToolbarActionsFactory() {
- ComponentToolbarActionsFactory::SetTestingFactory(nullptr);
-}
-
-ScopedVector<ToolbarActionViewController>
-MockComponentToolbarActionsFactory::GetComponentToolbarActions(
- Browser* browser) {
- ScopedVector<ToolbarActionViewController> component_actions;
- TestToolbarActionViewController* action =
- new TestToolbarActionViewController(kMockId);
- component_actions.push_back(action);
- return component_actions.Pass();
-}
-
-} // namespace
-
class ComponentToolbarActionsBrowserTest : public InProcessBrowserTest {
protected:
ComponentToolbarActionsBrowserTest() {}
@@ -100,10 +49,11 @@ IN_PROC_BROWSER_TEST_F(ComponentToolbarActionsBrowserTest,
// Even though the method says "ExtensionId", this actually refers to any id
// for the action.
- EXPECT_EQ(kMockId, browser_actions_bar.GetExtensionId(0));
+ EXPECT_EQ(ComponentToolbarActionsFactory::kActionIdForTesting,
+ browser_actions_bar.GetExtensionId(0));
// There should only have been one created component action.
- const std::vector<std::string> action_ids = mock_factory()->action_ids();
+ const std::vector<std::string>& action_ids = mock_factory()->action_ids();
ASSERT_EQ(1u, action_ids.size());
const std::vector<ToolbarActionViewController*>& actions =
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
index 8f64c07..62b05a3 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
@@ -20,8 +20,13 @@ base::LazyInstance<ComponentToolbarActionsFactory> lazy_factory =
} // namespace
-ComponentToolbarActionsFactory::ComponentToolbarActionsFactory()
- : num_component_actions_(-1) {}
+// static
+const char ComponentToolbarActionsFactory::kMediaRouterActionId[] =
+ "media_router_action";
+const char ComponentToolbarActionsFactory::kActionIdForTesting[] =
+ "mock_action";
+
+ComponentToolbarActionsFactory::ComponentToolbarActionsFactory() {}
ComponentToolbarActionsFactory::~ComponentToolbarActionsFactory() {}
// static
@@ -29,6 +34,26 @@ ComponentToolbarActionsFactory* ComponentToolbarActionsFactory::GetInstance() {
return testing_factory_ ? testing_factory_ : &lazy_factory.Get();
}
+// static
+std::vector<std::string> ComponentToolbarActionsFactory::GetComponentIds() {
+ std::vector<std::string> component_ids;
+
+ // This is currently behind the extension-action-redesign flag, as it is
+ // designed for the new toolbar.
+ if (!extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
+ return component_ids;
+
+ if (testing_factory_) {
+ component_ids.push_back(
+ ComponentToolbarActionsFactory::kActionIdForTesting);
+ } else if (switches::MediaRouterEnabled()) {
+ component_ids.push_back(
+ ComponentToolbarActionsFactory::kMediaRouterActionId);
+ }
+
+ return component_ids;
+}
+
ScopedVector<ToolbarActionViewController>
ComponentToolbarActionsFactory::GetComponentToolbarActions(Browser* browser) {
ScopedVector<ToolbarActionViewController> component_actions;
@@ -45,23 +70,12 @@ ComponentToolbarActionsFactory::GetComponentToolbarActions(Browser* browser) {
// should be okay. If this changes, we should rethink this design to have,
// e.g., RegisterChromeAction().
-#if defined(ENABLE_MEDIA_ROUTER)
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- ::switches::kEnableMediaRouter)) {
+ if (switches::MediaRouterEnabled())
component_actions.push_back(new MediaRouterAction(browser));
- }
-#endif
return component_actions.Pass();
}
-int ComponentToolbarActionsFactory::GetNumComponentActions(Browser* browser) {
- if (num_component_actions_ == -1)
- num_component_actions_ = GetComponentToolbarActions(browser).size();
-
- return num_component_actions_;
-}
-
// static
void ComponentToolbarActionsFactory::SetTestingFactory(
ComponentToolbarActionsFactory* factory) {
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
index 9a205ed..6bdee8e 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
@@ -17,28 +17,28 @@ class ToolbarActionViewController;
// components of chrome, such as ChromeCast.
class ComponentToolbarActionsFactory {
public:
+ // Component action IDs.
+ static const char kMediaRouterActionId[];
+ static const char kActionIdForTesting[]; // Only used for testing.
+
ComponentToolbarActionsFactory();
- ~ComponentToolbarActionsFactory();
+ virtual ~ComponentToolbarActionsFactory();
static ComponentToolbarActionsFactory* GetInstance();
- // Returns a collection of controllers for Chrome Actions. Declared virtual
- // for testing.
+ // Returns a vector of IDs of the component actions.
+ static std::vector<std::string> GetComponentIds();
+
+ // Returns a collection of controllers for component actions. Declared
+ // virtual for testing.
virtual ScopedVector<ToolbarActionViewController>
GetComponentToolbarActions(Browser* browser);
- // Returns the number of component actions.
- int GetNumComponentActions(Browser* browser);
-
// Sets the factory to use for testing purposes.
// Ownership remains with the caller.
static void SetTestingFactory(ComponentToolbarActionsFactory* factory);
private:
- // The number of component actions. Initially set to -1 to denote that the
- // count has not been checked yet.
- int num_component_actions_;
-
DISALLOW_COPY_AND_ASSIGN(ComponentToolbarActionsFactory);
};
diff --git a/chrome/browser/ui/toolbar/media_router_action.cc b/chrome/browser/ui/toolbar/media_router_action.cc
index cdfa0ae..eebe5de 100644
--- a/chrome/browser/ui/toolbar/media_router_action.cc
+++ b/chrome/browser/ui/toolbar/media_router_action.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/media/router/media_router_mojo_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
#include "chrome/browser/ui/toolbar/media_router_action_platform_delegate.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
#include "chrome/grit/generated_resources.h"
@@ -26,22 +27,23 @@ using media_router::MediaRouterDialogController;
MediaRouterAction::MediaRouterAction(Browser* browser)
: media_router::IssuesObserver(GetMediaRouter(browser)),
media_router::MediaRoutesObserver(GetMediaRouter(browser)),
- id_("media_router_action"),
+ id_(ComponentToolbarActionsFactory::kMediaRouterActionId),
name_(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_TITLE)),
- media_router_active_icon_(ui::ResourceBundle::GetSharedInstance().
- GetImageNamed(IDR_MEDIA_ROUTER_ACTIVE_ICON)),
- media_router_error_icon_(ui::ResourceBundle::GetSharedInstance().
- GetImageNamed(IDR_MEDIA_ROUTER_ERROR_ICON)),
- media_router_idle_icon_(ui::ResourceBundle::GetSharedInstance().
- GetImageNamed(IDR_MEDIA_ROUTER_IDLE_ICON)),
- media_router_warning_icon_(ui::ResourceBundle::GetSharedInstance().
- GetImageNamed(IDR_MEDIA_ROUTER_WARNING_ICON)),
+ media_router_active_icon_(
+ ui::ResourceBundle::GetSharedInstance()
+ .GetImageNamed(IDR_MEDIA_ROUTER_ACTIVE_ICON)),
+ media_router_error_icon_(ui::ResourceBundle::GetSharedInstance()
+ .GetImageNamed(IDR_MEDIA_ROUTER_ERROR_ICON)),
+ media_router_idle_icon_(ui::ResourceBundle::GetSharedInstance()
+ .GetImageNamed(IDR_MEDIA_ROUTER_IDLE_ICON)),
+ media_router_warning_icon_(
+ ui::ResourceBundle::GetSharedInstance()
+ .GetImageNamed(IDR_MEDIA_ROUTER_WARNING_ICON)),
current_icon_(&media_router_idle_icon_),
has_local_route_(false),
delegate_(nullptr),
platform_delegate_(MediaRouterActionPlatformDelegate::Create(browser)),
- contextual_menu_(browser) {
-}
+ contextual_menu_(browser) {}
MediaRouterAction::~MediaRouterAction() {
}
@@ -101,7 +103,7 @@ ui::MenuModel* MediaRouterAction::GetContextMenu() {
}
bool MediaRouterAction::CanDrag() const {
- return false;
+ return true;
}
bool MediaRouterAction::ExecuteAction(bool by_user) {
@@ -112,6 +114,8 @@ bool MediaRouterAction::ExecuteAction(bool by_user) {
}
void MediaRouterAction::UpdateState() {
+ if (delegate_)
+ delegate_->UpdateState();
}
bool MediaRouterAction::DisabledClickOpensMenu() const {
diff --git a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
new file mode 100644
index 0000000..9694d90
--- /dev/null
+++ b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 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/toolbar/mock_component_toolbar_actions_factory.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
+#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
+
+MockComponentToolbarActionsFactory::MockComponentToolbarActionsFactory(
+ Browser* browser) {
+ ComponentToolbarActionsFactory::SetTestingFactory(this);
+
+ ScopedVector<ToolbarActionViewController> actions =
+ GetComponentToolbarActions(browser);
+ for (const ToolbarActionViewController* action : actions)
+ action_ids_.push_back(action->GetId());
+}
+
+MockComponentToolbarActionsFactory::~MockComponentToolbarActionsFactory() {
+ ComponentToolbarActionsFactory::SetTestingFactory(nullptr);
+}
+
+ScopedVector<ToolbarActionViewController>
+MockComponentToolbarActionsFactory::GetComponentToolbarActions(
+ Browser* browser) {
+ ScopedVector<ToolbarActionViewController> component_actions;
+ component_actions.push_back(new TestToolbarActionViewController(
+ ComponentToolbarActionsFactory::kActionIdForTesting));
+ return component_actions.Pass();
+}
diff --git a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
new file mode 100644
index 0000000..abf9d1b
--- /dev/null
+++ b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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_TOOLBAR_MOCK_COMPONENT_TOOLBAR_ACTIONS_FACTORY_H_
+#define CHROME_BROWSER_UI_TOOLBAR_MOCK_COMPONENT_TOOLBAR_ACTIONS_FACTORY_H_
+
+#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
+
+class Browser;
+
+// Mock class used to substitute ComponentToolbarActionsFactory in tests.
+class MockComponentToolbarActionsFactory
+ : public ComponentToolbarActionsFactory {
+ public:
+ explicit MockComponentToolbarActionsFactory(Browser* browser);
+ ~MockComponentToolbarActionsFactory() override;
+
+ // ComponentToolbarActionsFactory:
+ ScopedVector<ToolbarActionViewController> GetComponentToolbarActions(
+ Browser* browser) override;
+
+ const std::vector<std::string>& action_ids() const { return action_ids_; }
+
+ private:
+ std::vector<std::string> action_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockComponentToolbarActionsFactory);
+};
+
+#endif // CHROME_BROWSER_UI_TOOLBAR_MOCK_COMPONENT_TOOLBAR_ACTIONS_FACTORY_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index 98ef0f6..c9836b2 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -25,6 +25,7 @@
#include "chrome/common/pref_names.h"
#include "components/crx_file/id_util.h"
#include "components/pref_registry/pref_registry_syncable.h"
+#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/runtime_data.h"
#include "extensions/common/extension.h"
@@ -119,7 +120,7 @@ ToolbarActionsBar::ToolbarActionsBar(ToolbarActionsBarDelegate* delegate,
ToolbarActionsBar* main_bar)
: delegate_(delegate),
browser_(browser),
- model_(extensions::ExtensionToolbarModel::Get(browser_->profile())),
+ model_(ToolbarActionsModel::Get(browser_->profile())),
main_bar_(main_bar),
platform_settings_(main_bar != nullptr),
popup_owner_(nullptr),
@@ -258,22 +259,9 @@ size_t ToolbarActionsBar::GetIconCount() const {
// icons than we have, and we should always have a view per item in the model.
// (The only exception is if this is in initialization.)
if (!toolbar_actions_.empty() && !suppress_layout_ &&
- model_->extensions_initialized()) {
- size_t num_extension_actions = 0u;
- for (ToolbarActionViewController* action : toolbar_actions_) {
- // No component action should ever have a valid extension id, so we can
- // use this to check the extension amount.
- if (crx_file::id_util::IdIsValid(action->GetId()))
- ++num_extension_actions;
- }
-
- int num_component_actions =
- ComponentToolbarActionsFactory::GetInstance()->
- GetNumComponentActions(browser_);
- size_t num_total_actions = num_extension_actions + num_component_actions;
-
- DCHECK_LE(visible_icons, num_total_actions);
- DCHECK_EQ(model_->toolbar_items().size(), num_extension_actions);
+ model_->actions_initialized()) {
+ DCHECK_LE(visible_icons, toolbar_actions_.size());
+ DCHECK_EQ(model_->toolbar_items().size(), toolbar_actions_.size());
}
#endif
@@ -331,7 +319,7 @@ void ToolbarActionsBar::CreateActions() {
DCHECK(toolbar_actions_.empty());
// We wait for the extension system to be initialized before we add any
// actions, as they rely on the extension system to function.
- if (!model_ || !model_->extensions_initialized())
+ if (!model_ || !model_->actions_initialized())
return;
{
@@ -342,37 +330,14 @@ void ToolbarActionsBar::CreateActions() {
// We don't redraw the view while creating actions.
base::AutoReset<bool> layout_resetter(&suppress_layout_, true);
- // Extension actions come first.
- extensions::ExtensionActionManager* action_manager =
- extensions::ExtensionActionManager::Get(browser_->profile());
- const extensions::ExtensionList& toolbar_items = model_->toolbar_items();
- for (const scoped_refptr<const extensions::Extension>& extension :
- toolbar_items) {
- toolbar_actions_.push_back(new ExtensionActionViewController(
- extension.get(),
- browser_,
- action_manager->GetExtensionAction(*extension),
- this));
- }
-
- // Component actions come second, and are suppressed if the extension
- // actions are being highlighted.
+ // Get the toolbar actions.
+ toolbar_actions_ = model_->CreateActions(browser_, this);
if (!model_->is_highlighting()) {
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/463337
// is fixed.
tracked_objects::ScopedTracker tracking_profile2(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"ToolbarActionsBar::CreateActions2"));
-
- ScopedVector<ToolbarActionViewController> component_actions =
- ComponentToolbarActionsFactory::GetInstance()->
- GetComponentToolbarActions(browser_);
- DCHECK(component_actions.empty() ||
- extensions::FeatureSwitch::extension_action_redesign()->IsEnabled());
- toolbar_actions_.insert(toolbar_actions_.end(),
- component_actions.begin(),
- component_actions.end());
- component_actions.weak_clear();
}
if (!toolbar_actions_.empty()) {
@@ -462,8 +427,8 @@ void ToolbarActionsBar::OnDragDrop(int dragged_index,
delta = -1;
else if (drag_type == DRAG_TO_MAIN)
delta = 1;
- model_->MoveExtensionIcon(toolbar_actions_[dragged_index]->GetId(),
- dropped_index);
+ model_->MoveActionIcon(toolbar_actions_[dragged_index]->GetId(),
+ dropped_index);
if (delta)
model_->SetVisibleIconCount(model_->visible_icon_count() + delta);
}
@@ -552,7 +517,7 @@ void ToolbarActionsBar::MaybeShowExtensionBubble(
// so wait until animation stops.
pending_extension_bubble_controller_ = controller.Pass();
} else {
- const extensions::ExtensionIdList& affected_extensions =
+ const std::vector<std::string>& affected_extensions =
controller->GetExtensionIdList();
ToolbarActionViewController* anchor_action = nullptr;
for (const std::string& id : affected_extensions) {
@@ -564,11 +529,20 @@ void ToolbarActionsBar::MaybeShowExtensionBubble(
}
}
-void ToolbarActionsBar::OnToolbarExtensionAdded(
- const extensions::Extension* extension,
- int index) {
- DCHECK(GetActionForId(extension->id()) == nullptr) <<
- "Asked to add a toolbar action view for an extension that already exists";
+void ToolbarActionsBar::OnToolbarActionAdded(const std::string& action_id,
+ int index) {
+ DCHECK(GetActionForId(action_id) == nullptr)
+ << "Asked to add a toolbar action view for an extension that already "
+ "exists";
+
+ // TODO(devlin): This is a minor layering violation and the model should pass
+ // in an action directly.
+ const extensions::Extension* extension =
+ extensions::ExtensionRegistry::Get(browser_->profile())
+ ->enabled_extensions()
+ .GetByID(action_id);
+ // Only extensions should be added after initialization.
+ DCHECK(extension);
toolbar_actions_.insert(
toolbar_actions_.begin() + index,
@@ -582,7 +556,7 @@ void ToolbarActionsBar::OnToolbarExtensionAdded(
delegate_->AddViewForAction(toolbar_actions_[index], index);
// If we are still initializing the container, don't bother animating.
- if (!model_->extensions_initialized())
+ if (!model_->actions_initialized())
return;
// We may need to resize (e.g. to show the new icon, or the chevron). We don't
@@ -596,10 +570,9 @@ void ToolbarActionsBar::OnToolbarExtensionAdded(
ResizeDelegate(gfx::Tween::LINEAR, true);
}
-void ToolbarActionsBar::OnToolbarExtensionRemoved(
- const extensions::Extension* extension) {
+void ToolbarActionsBar::OnToolbarActionRemoved(const std::string& action_id) {
ToolbarActions::iterator iter = toolbar_actions_.begin();
- while (iter != toolbar_actions_.end() && (*iter)->GetId() != extension->id())
+ while (iter != toolbar_actions_.end() && (*iter)->GetId() != action_id)
++iter;
if (iter == toolbar_actions_.end())
@@ -617,11 +590,11 @@ void ToolbarActionsBar::OnToolbarExtensionRemoved(
// because the icon is just going to get re-added to the same location.
// There is an exception if this is an off-the-record profile, and the
// extension is no longer incognito-enabled.
- if (!extensions::ExtensionSystem::Get(browser_->profile())->runtime_data()->
- IsBeingUpgraded(extension->id()) ||
+ if (!extensions::ExtensionSystem::Get(browser_->profile())
+ ->runtime_data()
+ ->IsBeingUpgraded(action_id) ||
(browser_->profile()->IsOffTheRecord() &&
- !extensions::util::IsIncognitoEnabled(extension->id(),
- browser_->profile()))) {
+ !extensions::util::IsIncognitoEnabled(action_id, browser_->profile()))) {
if (toolbar_actions_.size() > model_->visible_icon_count()) {
// If we have more icons than we can show, then we must not be changing
// the container size (since we either removed an icon from the main
@@ -639,9 +612,8 @@ void ToolbarActionsBar::OnToolbarExtensionRemoved(
SetOverflowedActionWantsToRun();
}
-void ToolbarActionsBar::OnToolbarExtensionMoved(
- const extensions::Extension* extension,
- int index) {
+void ToolbarActionsBar::OnToolbarActionMoved(const std::string& action_id,
+ int index) {
DCHECK(index >= 0 && index < static_cast<int>(toolbar_actions_.size()));
// Unfortunately, |index| doesn't really mean a lot to us, because this
// window's toolbar could be different (if actions are popped out). Just
@@ -649,9 +621,8 @@ void ToolbarActionsBar::OnToolbarExtensionMoved(
ReorderActions();
}
-void ToolbarActionsBar::OnToolbarExtensionUpdated(
- const extensions::Extension* extension) {
- ToolbarActionViewController* action = GetActionForId(extension->id());
+void ToolbarActionsBar::OnToolbarActionUpdated(const std::string& action_id) {
+ ToolbarActionViewController* action = GetActionForId(action_id);
// There might not be a view in cases where we are highlighting or if we
// haven't fully initialized the actions.
if (action) {
@@ -660,14 +631,13 @@ void ToolbarActionsBar::OnToolbarExtensionUpdated(
}
}
-bool ToolbarActionsBar::ShowExtensionActionPopup(
- const extensions::Extension* extension,
- bool grant_active_tab) {
+bool ToolbarActionsBar::ShowToolbarActionPopup(const std::string& action_id,
+ bool grant_active_tab) {
// Don't override another popup, and only show in the active window.
if (popup_owner() || !browser_->window()->IsActive())
return false;
- ToolbarActionViewController* action = GetActionForId(extension->id());
+ ToolbarActionViewController* action = GetActionForId(action_id);
return action && action->ExecuteAction(grant_active_tab);
}
@@ -697,7 +667,7 @@ void ToolbarActionsBar::ResizeDelegate(gfx::Tween::Type tween_type,
}
void ToolbarActionsBar::OnToolbarHighlightModeChanged(bool is_highlighting) {
- if (!model_->extensions_initialized())
+ if (!model_->actions_initialized())
return;
// It's a bit of a pain that we delete and recreate everything here, but given
// everything else going on (the lack of highlight, [n] more extensions
@@ -733,8 +703,8 @@ void ToolbarActionsBar::ReorderActions() {
// First, reset the order to that of the model.
auto compare = [](ToolbarActionViewController* const& action,
- const scoped_refptr<const extensions::Extension>& ext) {
- return action->GetId() == ext->id();
+ const ToolbarActionsModel::ToolbarItem& item) {
+ return action->GetId() == item.id;
};
SortContainer(&toolbar_actions_.get(), model_->toolbar_items(), compare);
@@ -769,9 +739,9 @@ void ToolbarActionsBar::SetOverflowedActionWantsToRun() {
}
ToolbarActionViewController* ToolbarActionsBar::GetActionForId(
- const std::string& id) {
+ const std::string& action_id) {
for (ToolbarActionViewController* action : toolbar_actions_) {
- if (action->GetId() == id)
+ if (action->GetId() == action_id)
return action;
}
return nullptr;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
index 149f720..af68242 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -10,8 +10,8 @@
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/size.h"
@@ -30,15 +30,14 @@ class ToolbarActionViewController;
// A platform-independent version of the container for toolbar actions,
// including extension actions and component actions.
// This class manages the order of the actions, the actions' state, and owns the
-// action controllers, in addition to (for extensions) interfacing with the
-// extension toolbar model. Further, it manages dimensions for the bar,
-// excluding animations.
+// action controllers, in addition to interfacing with the toolbar actions
+// model. Further, it manages dimensions for the bar, excluding animations.
// This can come in two flavors, main and "overflow". The main bar is visible
// next to the omnibox, and the overflow bar is visible inside the chrome
// (fka wrench) menu. The main bar can have only a single row of icons with
// flexible width, whereas the overflow bar has multiple rows of icons with a
// fixed width (the width of the menu).
-class ToolbarActionsBar : public extensions::ExtensionToolbarModel::Observer {
+class ToolbarActionsBar : public ToolbarActionsModel::Observer {
public:
// A struct to contain the platform settings.
struct PlatformSettings {
@@ -178,9 +177,9 @@ class ToolbarActionsBar : public extensions::ExtensionToolbarModel::Observer {
return suppress_animation_ || disable_animations_for_testing_;
}
bool is_highlighting() const { return model_ && model_->is_highlighting(); }
- extensions::ExtensionToolbarModel::HighlightType highlight_type() const {
+ ToolbarActionsModel::HighlightType highlight_type() const {
return model_ ? model_->highlight_type()
- : extensions::ExtensionToolbarModel::HIGHLIGHT_NONE;
+ : ToolbarActionsModel::HIGHLIGHT_NONE;
}
const PlatformSettings& platform_settings() const {
return platform_settings_;
@@ -206,17 +205,13 @@ class ToolbarActionsBar : public extensions::ExtensionToolbarModel::Observer {
private:
using ToolbarActions = ScopedVector<ToolbarActionViewController>;
- // ExtensionToolbarModel::Observer:
- void OnToolbarExtensionAdded(const extensions::Extension* extension,
- int index) override;
- void OnToolbarExtensionRemoved(
- const extensions::Extension* extension) override;
- void OnToolbarExtensionMoved(const extensions::Extension* extension,
- int index) override;
- void OnToolbarExtensionUpdated(
- const extensions::Extension* extension) override;
- bool ShowExtensionActionPopup(const extensions::Extension* extension,
- bool grant_active_tab) override;
+ // ToolbarActionsModel::Observer:
+ void OnToolbarActionAdded(const std::string& action_id, int index) override;
+ void OnToolbarActionRemoved(const std::string& action_id) override;
+ void OnToolbarActionMoved(const std::string& action_id, int index) override;
+ void OnToolbarActionUpdated(const std::string& action_id) override;
+ bool ShowToolbarActionPopup(const std::string& action_id,
+ bool grant_active_tab) override;
void OnToolbarVisibleCountChanged() override;
void OnToolbarHighlightModeChanged(bool is_highlighting) override;
void OnToolbarModelInitialized() override;
@@ -227,7 +222,7 @@ class ToolbarActionsBar : public extensions::ExtensionToolbarModel::Observer {
void ResizeDelegate(gfx::Tween::Type tween_type, bool suppress_chevron);
// Returns the action for the given |id|, if one exists.
- ToolbarActionViewController* GetActionForId(const std::string& id);
+ ToolbarActionViewController* GetActionForId(const std::string& action_id);
// Returns the current web contents.
content::WebContents* GetCurrentWebContents();
@@ -251,7 +246,7 @@ class ToolbarActionsBar : public extensions::ExtensionToolbarModel::Observer {
Browser* browser_;
// The observed toolbar model.
- extensions::ExtensionToolbarModel* model_;
+ ToolbarActionsModel* model_;
// The controller for the main toolbar actions bar. This will be null if this
// is the main bar.
@@ -267,8 +262,8 @@ class ToolbarActionsBar : public extensions::ExtensionToolbarModel::Observer {
// from toolbar_actions_).
ToolbarActionViewController* popup_owner_;
- ScopedObserver<extensions::ExtensionToolbarModel,
- extensions::ExtensionToolbarModel::Observer> model_observer_;
+ ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer>
+ model_observer_;
// True if we should suppress layout, such as when we are creating or
// adjusting a lot of actions at once.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
index c1ddfc3..18fab96 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -320,7 +320,7 @@ TEST_F(ToolbarActionsBarUnitTest, ToolbarActionsReorderOnPrefChange) {
EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
}
- extensions::ExtensionIdList new_order;
+ std::vector<std::string> new_order;
new_order.push_back(toolbar_actions_bar()->toolbar_actions_unordered()[1]->
GetId());
new_order.push_back(toolbar_actions_bar()->toolbar_actions_unordered()[2]->
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.h b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.h
index dd72905..268245a 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.h
@@ -75,9 +75,7 @@ class ToolbarActionsBarUnitTest : public BrowserWithTestWindowTest {
ToolbarActionsBar* overflow_bar() {
return overflow_browser_action_test_util_->GetToolbarActionsBar();
}
- extensions::ExtensionToolbarModel* toolbar_model() {
- return toolbar_model_;
- }
+ ToolbarActionsModel* toolbar_model() { return toolbar_model_; }
BrowserActionTestUtil* browser_action_test_util() {
return browser_action_test_util_.get();
}
@@ -86,8 +84,8 @@ class ToolbarActionsBarUnitTest : public BrowserWithTestWindowTest {
}
private:
- // The associated ExtensionToolbarModel (owned by the keyed service setup).
- extensions::ExtensionToolbarModel* toolbar_model_;
+ // The associated ToolbarActionsModel (owned by the keyed service setup).
+ ToolbarActionsModel* toolbar_model_;
// A BrowserActionTestUtil object constructed with the associated
// ToolbarActionsBar.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
new file mode 100644
index 0000000..a9a770f
--- /dev/null
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -0,0 +1,844 @@
+// 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/toolbar/toolbar_actions_model.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/location.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_action_manager.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/extensions/extension_action_view_controller.h"
+#include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
+#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/pref_names.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/one_shot_event.h"
+
+ToolbarActionsModel::ToolbarActionsModel(
+ Profile* profile,
+ extensions::ExtensionPrefs* extension_prefs)
+ : profile_(profile),
+ extension_prefs_(extension_prefs),
+ prefs_(profile_->GetPrefs()),
+ extension_action_api_(extensions::ExtensionActionAPI::Get(profile_)),
+ extension_registry_(extensions::ExtensionRegistry::Get(profile_)),
+ actions_initialized_(false),
+ use_redesign_(extensions::FeatureSwitch::extension_action_redesign()
+ ->IsEnabled()),
+ highlight_type_(HIGHLIGHT_NONE),
+ extension_action_observer_(this),
+ extension_registry_observer_(this),
+ weak_ptr_factory_(this) {
+ extensions::ExtensionSystem::Get(profile_)->ready().Post(
+ FROM_HERE, base::Bind(&ToolbarActionsModel::OnReady,
+ weak_ptr_factory_.GetWeakPtr()));
+ visible_icon_count_ =
+ prefs_->GetInteger(extensions::pref_names::kToolbarSize);
+
+ // We only care about watching the prefs if not in incognito mode.
+ if (!profile_->IsOffTheRecord()) {
+ pref_change_registrar_.Init(prefs_);
+ pref_change_callback_ =
+ base::Bind(&ToolbarActionsModel::OnActionToolbarPrefChange,
+ base::Unretained(this));
+ pref_change_registrar_.Add(extensions::pref_names::kToolbar,
+ pref_change_callback_);
+ }
+}
+
+ToolbarActionsModel::~ToolbarActionsModel() {}
+
+// static
+ToolbarActionsModel* ToolbarActionsModel::Get(Profile* profile) {
+ return ToolbarActionsModelFactory::GetForProfile(profile);
+}
+
+void ToolbarActionsModel::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ToolbarActionsModel::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void ToolbarActionsModel::MoveActionIcon(const std::string& id, size_t index) {
+ std::vector<ToolbarItem>::iterator pos = toolbar_items_.begin();
+ while (pos != toolbar_items_.end() && (*pos).id != id)
+ ++pos;
+ if (pos == toolbar_items_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ ToolbarItem action = *pos;
+ toolbar_items_.erase(pos);
+
+ std::vector<std::string>::iterator pos_id =
+ std::find(last_known_positions_.begin(), last_known_positions_.end(), id);
+ if (pos_id != last_known_positions_.end())
+ last_known_positions_.erase(pos_id);
+
+ if (index < toolbar_items_.size()) {
+ // If the index is not at the end, find the item currently at |index|, and
+ // insert |action| before it in |toolbar_items_| and |action|'s id in
+ // |last_known_positions_|.
+ std::vector<ToolbarItem>::iterator iter = toolbar_items_.begin() + index;
+ last_known_positions_.insert(
+ std::find(last_known_positions_.begin(), last_known_positions_.end(),
+ iter->id),
+ id);
+ toolbar_items_.insert(iter, action);
+ } else {
+ // Otherwise, put |action| and |id| at the end.
+ DCHECK_EQ(toolbar_items_.size(), index);
+ toolbar_items_.push_back(action);
+ last_known_positions_.push_back(id);
+ }
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnToolbarActionMoved(id, index));
+ MaybeUpdateVisibilityPref(action, index);
+ UpdatePrefs();
+}
+
+void ToolbarActionsModel::SetVisibleIconCount(size_t count) {
+ visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count;
+
+ // Only set the prefs if we're not in highlight mode and the profile is not
+ // incognito. Highlight mode is designed to be a transitory state, and should
+ // not persist across browser restarts (though it may be re-entered), and we
+ // don't store anything in incognito.
+ if (!is_highlighting() && !profile_->IsOffTheRecord()) {
+ // Additionally, if we are using the new toolbar, any icons which are in the
+ // overflow menu are considered "hidden". But it so happens that the times
+ // we are likely to call SetVisibleIconCount() are also those when we are
+ // in flux. So wait for things to cool down before setting the prefs.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&ToolbarActionsModel::MaybeUpdateVisibilityPrefs,
+ weak_ptr_factory_.GetWeakPtr()));
+ prefs_->SetInteger(extensions::pref_names::kToolbarSize,
+ visible_icon_count_);
+ }
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnToolbarVisibleCountChanged());
+}
+
+void ToolbarActionsModel::OnExtensionActionUpdated(
+ ExtensionAction* extension_action,
+ content::WebContents* web_contents,
+ content::BrowserContext* browser_context) {
+ // Notify observers if the extension exists and is in the model.
+ if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
+ ToolbarItem(extension_action->extension_id(),
+ EXTENSION_ACTION)) != toolbar_items_.end()) {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarActionUpdated(extension_action->extension_id()));
+ }
+}
+
+ScopedVector<ToolbarActionViewController> ToolbarActionsModel::CreateActions(
+ Browser* browser,
+ ToolbarActionsBar* bar) {
+ DCHECK(browser);
+ DCHECK(bar);
+ ScopedVector<ToolbarActionViewController> action_list;
+
+ // Get the component action list.
+ ScopedVector<ToolbarActionViewController> component_actions =
+ ComponentToolbarActionsFactory::GetInstance()->GetComponentToolbarActions(
+ browser);
+
+ extensions::ExtensionActionManager* action_manager =
+ extensions::ExtensionActionManager::Get(profile_);
+
+ // toolbar_items() might not equate to toolbar_items_ in the case where a
+ // subset are highlighted.
+ std::vector<ToolbarItem> items = toolbar_items();
+ for (const ToolbarItem& action : items) {
+ if (action.type == EXTENSION_ACTION) {
+ // Get the extension.
+ const extensions::Extension* extension = GetExtensionById(action.id);
+ DCHECK(extension);
+
+ // Create and add an ExtensionActionViewController for the extension.
+ action_list.push_back(new ExtensionActionViewController(
+ extension, browser, action_manager->GetExtensionAction(*extension),
+ bar));
+ } else if (action.type == COMPONENT_ACTION) {
+ DCHECK(use_redesign_);
+ // Find the corresponding action to |action|.
+ for (auto component_action : component_actions) {
+ if (component_action->GetId() == action.id) {
+ action_list.push_back(component_action);
+ break;
+ }
+ }
+ }
+ }
+
+ // We've moved ownership of the subset of the component actions that we
+ // kept track of via toolbar_items() from |component_actions| to
+ // |action_list|, so we don't need to keep track of these.
+ component_actions.weak_clear();
+
+ return action_list.Pass();
+}
+
+void ToolbarActionsModel::OnExtensionActionVisibilityChanged(
+ const std::string& extension_id,
+ bool is_now_visible) {
+ // Hiding works differently with the new and old toolbars.
+ if (use_redesign_) {
+ // It's possible that we haven't added this action yet, if its
+ // visibility was adjusted in the course of its initialization.
+ if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
+ ToolbarItem(extension_id, EXTENSION_ACTION)) ==
+ toolbar_items_.end())
+ return;
+
+ int new_size = 0;
+ int new_index = 0;
+ if (is_now_visible) {
+ // If this action used to be hidden, we can't possibly be showing all.
+ DCHECK_LT(visible_icon_count(), toolbar_items_.size());
+ // Grow the bar by one and move the action to the end of the visibles.
+ new_size = visible_icon_count() + 1;
+ new_index = new_size - 1;
+ } else {
+ // If we're hiding one, we must be showing at least one.
+ DCHECK_GE(visible_icon_count(), 0u);
+ // Shrink the bar by one and move the action to the beginning of the
+ // overflow menu.
+ new_size = visible_icon_count() - 1;
+ new_index = new_size;
+ }
+ SetVisibleIconCount(new_size);
+ MoveActionIcon(extension_id, new_index);
+ } else { // Don't include all extensions.
+ const extensions::Extension* extension = GetExtensionById(extension_id);
+ if (is_now_visible)
+ AddExtension(extension);
+ else
+ RemoveExtension(extension);
+ }
+}
+
+void ToolbarActionsModel::OnExtensionLoaded(
+ content::BrowserContext* browser_context,
+ const extensions::Extension* extension) {
+ // We don't want to add the same extension twice. It may have already been
+ // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user
+ // hides the browser action and then disables and enables the extension.
+ if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
+ ToolbarItem(extension->id(), EXTENSION_ACTION)) !=
+ toolbar_items_.end())
+ return;
+
+ AddExtension(extension);
+}
+
+void ToolbarActionsModel::OnExtensionUnloaded(
+ content::BrowserContext* browser_context,
+ const extensions::Extension* extension,
+ extensions::UnloadedExtensionInfo::Reason reason) {
+ RemoveExtension(extension);
+}
+
+void ToolbarActionsModel::OnExtensionUninstalled(
+ content::BrowserContext* browser_context,
+ const extensions::Extension* extension,
+ extensions::UninstallReason reason) {
+ // Remove the extension id from the ordered list, if it exists (the extension
+ // might not be represented in the list because it might not have an icon).
+ std::vector<std::string>::iterator pos =
+ std::find(last_known_positions_.begin(), last_known_positions_.end(),
+ extension->id());
+
+ if (pos != last_known_positions_.end()) {
+ last_known_positions_.erase(pos);
+ UpdatePrefs();
+ }
+}
+
+void ToolbarActionsModel::OnReady() {
+ InitializeActionList();
+ // Wait until the extension system is ready before observing any further
+ // changes so that the toolbar buttons can be shown in their stable ordering
+ // taken from prefs.
+ extension_registry_observer_.Add(extension_registry_);
+ extension_action_observer_.Add(extension_action_api_);
+
+ if (ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
+ profile_)) {
+ std::vector<std::string> ids;
+ for (const ToolbarItem& action : toolbar_items_)
+ ids.push_back(action.id);
+ HighlightActions(ids, HIGHLIGHT_INFO);
+ }
+
+ actions_initialized_ = true;
+ FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized());
+}
+
+size_t ToolbarActionsModel::FindNewPositionFromLastKnownGood(
+ const ToolbarItem& action) {
+ // See if we have last known good position for this action.
+ size_t new_index = 0;
+ // Loop through the ID list of known positions, to count the number of
+ // visible action icons preceding |action|'s id.
+ for (const std::string& last_pos_id : last_known_positions_) {
+ if (last_pos_id == action.id)
+ return new_index; // We've found the right position.
+ // Found an action, need to see if it is visible.
+ for (const ToolbarItem& item : toolbar_items_) {
+ if (item.id == last_pos_id) {
+ // This extension is visible, update the index value.
+ ++new_index;
+ break;
+ }
+ }
+ }
+
+ // Position not found.
+ return toolbar_items_.size();
+}
+
+bool ToolbarActionsModel::ShouldAddExtension(
+ const extensions::Extension* extension) {
+ // In incognito mode, don't add any extensions that aren't incognito-enabled.
+ if (profile_->IsOffTheRecord() &&
+ !extensions::util::IsIncognitoEnabled(extension->id(), profile_))
+ return false;
+
+ extensions::ExtensionActionManager* action_manager =
+ extensions::ExtensionActionManager::Get(profile_);
+ if (use_redesign_) {
+ // In this case, we don't care about the browser action visibility, because
+ // we want to show each extension regardless.
+ return action_manager->GetExtensionAction(*extension) != NULL;
+ }
+
+ return action_manager->GetBrowserAction(*extension) &&
+ extension_action_api_->GetBrowserActionVisibility(extension->id());
+}
+
+void ToolbarActionsModel::AddExtension(const extensions::Extension* extension) {
+ // We only use AddExtension() once the system is initialized.
+ DCHECK(actions_initialized_);
+ if (!ShouldAddExtension(extension))
+ return;
+
+ // See if we have a last known good position for this extension.
+ bool is_new_extension =
+ std::find(last_known_positions_.begin(), last_known_positions_.end(),
+ extension->id()) == last_known_positions_.end();
+
+ // New extensions go at the right (end) of the visible extensions. Other
+ // extensions go at their previous position.
+ size_t new_index = 0;
+ if (is_new_extension) {
+ new_index = extensions::Manifest::IsComponentLocation(extension->location())
+ ? 0
+ : visible_icon_count();
+ // For the last-known position, we use the index of the extension that is
+ // just before this extension, plus one. (Note that this isn't the same
+ // as new_index + 1, because last_known_positions_ can include disabled
+ // extensions.)
+ int new_last_known_index =
+ new_index == 0 ? 0 : std::find(last_known_positions_.begin(),
+ last_known_positions_.end(),
+ toolbar_items_[new_index - 1].id) -
+ last_known_positions_.begin() + 1;
+ // In theory, the extension before this one should always
+ // be in last known positions, but if something funny happened with prefs,
+ // make sure we handle it.
+ // TODO(devlin): Track down these cases so we can CHECK this.
+ new_last_known_index =
+ std::min<int>(new_last_known_index, last_known_positions_.size());
+ last_known_positions_.insert(
+ last_known_positions_.begin() + new_last_known_index, extension->id());
+ UpdatePrefs();
+ } else {
+ new_index = FindNewPositionFromLastKnownGood(
+ ToolbarItem(extension->id(), EXTENSION_ACTION));
+ }
+
+ toolbar_items_.insert(toolbar_items_.begin() + new_index,
+ ToolbarItem(extension->id(), EXTENSION_ACTION));
+
+ // If we're currently highlighting, then even though we add a browser action
+ // to the full list (|toolbar_items_|, there won't be another *visible*
+ // browser action, which was what the observers care about.
+ if (!is_highlighting()) {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarActionAdded(extension->id(), new_index));
+
+ int visible_count_delta = 0;
+ if (is_new_extension && !all_icons_visible()) {
+ // If this is a new extension (and not all extensions are visible), we
+ // expand the toolbar out so that the new one can be seen.
+ visible_count_delta = 1;
+ } else if (profile_->IsOffTheRecord()) {
+ // If this is an incognito profile, we also have to check to make sure the
+ // overflow matches the main bar's status.
+ ToolbarActionsModel* main_model =
+ ToolbarActionsModel::Get(profile_->GetOriginalProfile());
+ // Find what the index will be in the main bar. Because Observer calls are
+ // nondeterministic, we can't just assume the main bar will have the
+ // extension and look it up.
+ size_t main_index = main_model->FindNewPositionFromLastKnownGood(
+ ToolbarItem(extension->id(), EXTENSION_ACTION));
+ bool visible = main_index < main_model->visible_icon_count();
+ // We may need to adjust the visible count if the incognito bar isn't
+ // showing all icons and this one is visible, or if it is showing all
+ // icons and this is hidden.
+ if (visible && !all_icons_visible())
+ visible_count_delta = 1;
+ else if (!visible && all_icons_visible())
+ visible_count_delta = -1;
+ }
+
+ if (visible_count_delta)
+ SetVisibleIconCount(visible_icon_count() + visible_count_delta);
+ }
+
+ MaybeUpdateVisibilityPref(ToolbarItem(extension->id(), EXTENSION_ACTION),
+ new_index);
+}
+
+void ToolbarActionsModel::RemoveExtension(
+ const extensions::Extension* extension) {
+ std::vector<ToolbarItem>::iterator pos =
+ std::find(toolbar_items_.begin(), toolbar_items_.end(),
+ ToolbarItem(extension->id(), EXTENSION_ACTION));
+
+ if (pos == toolbar_items_.end())
+ return;
+
+ size_t index = pos - toolbar_items_.begin();
+ // If the removed extension was on the toolbar, a new one will take its place
+ // if there are any in overflow.
+ bool new_extension_shown =
+ !all_icons_visible() && index < visible_icon_count();
+
+ // If our visible count is set to the current size, we need to decrement it.
+ if (visible_icon_count_ == static_cast<int>(toolbar_items_.size()))
+ SetVisibleIconCount(toolbar_items_.size() - 1);
+
+ toolbar_items_.erase(pos);
+
+ // If we're in highlight mode, we also have to remove the extension from
+ // the highlighted list.
+ if (is_highlighting()) {
+ pos = std::find(highlighted_items_.begin(), highlighted_items_.end(),
+ ToolbarItem(extension->id(), EXTENSION_ACTION));
+ if (pos != highlighted_items_.end()) {
+ highlighted_items_.erase(pos);
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarActionRemoved(extension->id()));
+ // If the highlighted list is now empty, we stop highlighting.
+ if (highlighted_items_.empty())
+ StopHighlighting();
+ }
+ } else {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarActionRemoved(extension->id()));
+ }
+
+ UpdatePrefs();
+ if (new_extension_shown) {
+ size_t newly_visible_index = visible_icon_count() - 1;
+ MaybeUpdateVisibilityPref(toolbar_items_[newly_visible_index],
+ newly_visible_index);
+ }
+}
+
+// Combine the currently enabled extensions that have browser actions (which
+// we get from the ExtensionRegistry) and component actions (which we get from
+// ComponentToolbarActionsFactory) with the ordering we get from the pref
+// service. For robustness we use a somewhat inefficient process:
+// 1. Create a vector of actions sorted by their pref values. This vector may
+// have holes.
+// 2. Create a vector of actions that did not have a pref value.
+// 3. Remove holes from the sorted vector and append the unsorted vector.
+void ToolbarActionsModel::InitializeActionList() {
+ DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet.
+
+ last_known_positions_ = extension_prefs_->GetToolbarOrder();
+ if (profile_->IsOffTheRecord())
+ IncognitoPopulate();
+ else
+ Populate(&last_known_positions_);
+
+ MaybeUpdateVisibilityPrefs();
+}
+
+void ToolbarActionsModel::Populate(std::vector<std::string>* positions) {
+ DCHECK(!profile_->IsOffTheRecord());
+
+ std::vector<ToolbarItem> all_actions;
+ // Ids of actions that have explicit positions.
+ std::vector<ToolbarItem> sorted(positions->size(), ToolbarItem());
+ // Ids of actions that don't have explicit positions.
+ std::vector<ToolbarItem> unsorted;
+
+ // Populate the lists.
+ int hidden = 0;
+ int browser_actions_count = 0;
+ int component_actions_count = 0;
+
+ // First, add the extension action ids to all_actions.
+ const extensions::ExtensionSet& extensions =
+ extension_registry_->enabled_extensions();
+ for (const scoped_refptr<const extensions::Extension>& extension :
+ extensions) {
+ if (!ShouldAddExtension(extension.get())) {
+ if (!extension_action_api_->GetBrowserActionVisibility(extension->id()))
+ ++hidden;
+ continue;
+ }
+
+ all_actions.push_back(ToolbarItem(extension->id(), EXTENSION_ACTION));
+ }
+
+ // Next, add the component action ids.
+ std::vector<std::string> component_ids =
+ ComponentToolbarActionsFactory::GetComponentIds();
+ for (const std::string& id : component_ids)
+ all_actions.push_back(ToolbarItem(id, COMPONENT_ACTION));
+
+ // Add each action id to the appropriate list.
+ for (const ToolbarItem& action : all_actions) {
+ std::vector<std::string>::const_iterator pos =
+ std::find(positions->begin(), positions->end(), action.id);
+ if (pos != positions->end()) {
+ sorted[pos - positions->begin()] = action;
+ } else {
+ // Unknown action - push it to the back of unsorted, and add it to the
+ // list of ids at the end.
+ unsorted.push_back(action);
+ positions->push_back(action.id);
+ }
+ }
+
+ // Merge the lists.
+ sorted.insert(sorted.end(), unsorted.begin(), unsorted.end());
+ toolbar_items_.reserve(sorted.size());
+
+ // We don't notify observers of the added extension yet. Rather, observers
+ // should wait for the "OnToolbarModelInitialized" notification, and then
+ // bulk-update. (This saves a lot of bouncing-back-and-forth here, and allows
+ // observers to ensure that the extension system is always initialized before
+ // using the extensions).
+ for (const ToolbarItem& action : sorted) {
+ if (action.type == EXTENSION_ACTION) {
+ // It's possible for the extension order to contain items that aren't
+ // actually loaded on this machine. For example, when extension sync is
+ // on, we sync the extension order as-is but double-check with the user
+ // before syncing NPAPI-containing extensions, so if one of those is not
+ // actually synced, we'll get a NULL in the list. This sort of case can
+ // also happen if some error prevents an extension from loading.
+ if (GetExtensionById(action.id)) {
+ toolbar_items_.push_back(ToolbarItem(action.id, EXTENSION_ACTION));
+ ++browser_actions_count;
+ }
+ } else if (action.type == COMPONENT_ACTION) {
+ toolbar_items_.push_back(ToolbarItem(action.id, COMPONENT_ACTION));
+ ++component_actions_count;
+ }
+ }
+
+ // Histogram names are prefixed with "ExtensionToolbarModel" rather than
+ // "ToolbarActionsModel" for historical reasons.
+ UMA_HISTOGRAM_COUNTS_100(
+ "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden);
+ UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount",
+ browser_actions_count);
+ UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.ComponentActionsCount",
+ component_actions_count);
+ UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.OverallActionsCount",
+ toolbar_items_.size());
+
+ if (!toolbar_items_.empty()) {
+ // Visible count can be -1, meaning: 'show all'. Since UMA converts negative
+ // values to 0, this would be counted as 'show none' unless we convert it to
+ // max.
+ UMA_HISTOGRAM_COUNTS_100(
+ "ExtensionToolbarModel.BrowserActionsVisible",
+ visible_icon_count_ == -1
+ ? visible_icon_count_
+ : visible_icon_count_ - component_actions_count);
+
+ if (use_redesign_) {
+ // The only time this will useful and possibly vary from
+ // BrowserActionsVisible is when the redesign has been enabled.
+ UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.ToolbarActionsVisible",
+ visible_icon_count_ == -1
+ ? base::HistogramBase::kSampleType_MAX
+ : visible_icon_count_);
+ }
+ }
+}
+
+void ToolbarActionsModel::IncognitoPopulate() {
+ DCHECK(profile_->IsOffTheRecord());
+ const ToolbarActionsModel* original_model =
+ ToolbarActionsModel::Get(profile_->GetOriginalProfile());
+
+ // Find the absolute value of the original model's count.
+ int original_visible = original_model->visible_icon_count();
+
+ // In incognito mode, we show only those actions that are incognito-enabled
+ // Further, any actions that were overflowed in regular mode are still
+ // overflowed. Order is the same as in regular mode.
+ visible_icon_count_ = 0;
+
+ for (std::vector<ToolbarItem>::const_iterator iter =
+ original_model->toolbar_items_.begin();
+ iter != original_model->toolbar_items_.end(); ++iter) {
+ // The extension might not be shown in incognito mode. For now, all
+ // component actions are present.
+ if (iter->type == EXTENSION_ACTION &&
+ !ShouldAddExtension(GetExtensionById(iter->id)))
+ continue;
+ toolbar_items_.push_back(*iter);
+ if (iter - original_model->toolbar_items_.begin() < original_visible)
+ ++visible_icon_count_;
+ }
+}
+
+void ToolbarActionsModel::UpdatePrefs() {
+ if (!extension_prefs_ || profile_->IsOffTheRecord())
+ return;
+
+ // Don't observe change caused by self.
+ pref_change_registrar_.Remove(extensions::pref_names::kToolbar);
+ extension_prefs_->SetToolbarOrder(last_known_positions_);
+ pref_change_registrar_.Add(extensions::pref_names::kToolbar,
+ pref_change_callback_);
+}
+
+void ToolbarActionsModel::MaybeUpdateVisibilityPref(const ToolbarItem& action,
+ size_t index) {
+ // Component actions don't have prefs to update.
+ if (action.type == COMPONENT_ACTION)
+ return;
+
+ // We only update the visibility pref for hidden/not hidden based on the
+ // overflow menu with the new toolbar design.
+ if (use_redesign_ && !profile_->IsOffTheRecord()) {
+ bool visible = index < visible_icon_count();
+ if (visible !=
+ extension_action_api_->GetBrowserActionVisibility(action.id)) {
+ // Don't observe changes caused by ourselves.
+ bool was_registered = false;
+ if (extension_action_observer_.IsObserving(extension_action_api_)) {
+ was_registered = true;
+ extension_action_observer_.RemoveAll();
+ }
+ extension_action_api_->SetBrowserActionVisibility(action.id, visible);
+ if (was_registered)
+ extension_action_observer_.Add(extension_action_api_);
+ }
+ }
+}
+
+void ToolbarActionsModel::MaybeUpdateVisibilityPrefs() {
+ for (size_t i = 0u; i < toolbar_items_.size(); ++i)
+ MaybeUpdateVisibilityPref(toolbar_items_[i], i);
+}
+
+void ToolbarActionsModel::OnActionToolbarPrefChange() {
+ // If extensions are not ready, defer to later Populate() call.
+ if (!actions_initialized_)
+ return;
+
+ // Recalculate |last_known_positions_| to be |pref_positions| followed by
+ // ones that are only in |last_known_positions_|.
+ std::vector<std::string> pref_positions = extension_prefs_->GetToolbarOrder();
+ size_t pref_position_size = pref_positions.size();
+ for (size_t i = 0; i < last_known_positions_.size(); ++i) {
+ if (std::find(pref_positions.begin(), pref_positions.end(),
+ last_known_positions_[i]) == pref_positions.end()) {
+ pref_positions.push_back(last_known_positions_[i]);
+ }
+ }
+ last_known_positions_.swap(pref_positions);
+
+ int desired_index = 0;
+ // Loop over the updated list of last known positions, moving any extensions
+ // that are in the wrong place.
+ for (const std::string& id : last_known_positions_) {
+ int current_index = GetIndexForId(id);
+ if (current_index == -1)
+ continue;
+ if (current_index != desired_index) {
+ ToolbarItem action = toolbar_items_[current_index];
+ toolbar_items_.erase(toolbar_items_.begin() + current_index);
+ toolbar_items_.insert(toolbar_items_.begin() + desired_index, action);
+ // Notify the observers to keep them up-to-date.
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarActionMoved(action.id, desired_index));
+ }
+ ++desired_index;
+ }
+
+ if (last_known_positions_.size() > pref_position_size) {
+ // Need to update pref because we have extra icons. But can't call
+ // UpdatePrefs() directly within observation closure.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&ToolbarActionsModel::UpdatePrefs,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+int ToolbarActionsModel::GetIndexForId(const std::string& id) const {
+ for (size_t i = 0; i < toolbar_items().size(); ++i) {
+ if (toolbar_items()[i].id == id)
+ return i;
+ }
+ return -1;
+}
+
+bool ToolbarActionsModel::ShowToolbarActionPopup(const std::string& id,
+ Browser* browser,
+ bool grant_active_tab) {
+ base::ObserverListBase<Observer>::Iterator it(&observers_);
+ Observer* obs = NULL;
+ // Look for the Observer associated with the browser.
+ // This would be cleaner if we had an abstract class for the Toolbar UI
+ // (like we do for LocationBar), but sadly, we don't.
+ while ((obs = it.GetNext()) != NULL) {
+ if (obs->GetBrowser() == browser)
+ return obs->ShowToolbarActionPopup(id, grant_active_tab);
+ }
+ return false;
+}
+
+void ToolbarActionsModel::EnsureVisibility(
+ const std::vector<std::string>& ids) {
+ if (all_icons_visible())
+ return; // Already showing all.
+
+ // Otherwise, make sure we have enough room to show all the extensions
+ // requested.
+ if (visible_icon_count() < ids.size())
+ SetVisibleIconCount(ids.size());
+
+ if (all_icons_visible())
+ return; // May have been set to max by SetVisibleIconCount.
+
+ // Guillotine's Delight: Move an orange noble to the front of the line.
+ for (std::vector<std::string>::const_iterator it = ids.begin();
+ it != ids.end(); ++it) {
+ for (std::vector<ToolbarItem>::const_iterator item = toolbar_items_.begin();
+ item != toolbar_items_.end(); ++item) {
+ if (item->id == *it) {
+ if (item - toolbar_items_.begin() >=
+ static_cast<int>(visible_icon_count()))
+ MoveActionIcon(*it, 0);
+ break;
+ }
+ }
+ }
+}
+
+bool ToolbarActionsModel::HighlightActions(const std::vector<std::string>& ids,
+ HighlightType highlight_type) {
+ highlighted_items_.clear();
+
+ for (const std::string& action_id : ids) {
+ for (const ToolbarItem& item : toolbar_items_) {
+ if (action_id == item.id)
+ highlighted_items_.push_back(item);
+ }
+ }
+
+ // If we have any items in |highlighted_items_|, then we entered highlighting
+ // mode.
+ if (highlighted_items_.size()) {
+ // It's important that is_highlighting_ is changed immediately before the
+ // observers are notified since it changes the result of toolbar_items().
+ highlight_type_ = highlight_type;
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarHighlightModeChanged(true));
+
+ // We set the visible icon count after the highlight mode change because
+ // the UI actions are created/destroyed during highlight, and doing that
+ // prior to changing the size allows us to still have smooth animations.
+ if (visible_icon_count() < ids.size())
+ SetVisibleIconCount(ids.size());
+
+ return true;
+ }
+
+ // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if
+ // we were otherwise in it).
+ if (is_highlighting())
+ StopHighlighting();
+ return false;
+}
+
+void ToolbarActionsModel::StopHighlighting() {
+ if (is_highlighting()) {
+ // It's important that is_highlighting_ is changed immediately before the
+ // observers are notified since it changes the result of toolbar_items().
+ highlight_type_ = HIGHLIGHT_NONE;
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnToolbarHighlightModeChanged(false));
+
+ // For the same reason, we don't clear highlighted_items_ until after the
+ // mode changed.
+ highlighted_items_.clear();
+
+ // We set the visible icon count after the highlight mode change because
+ // the UI actions are created/destroyed during highlight, and doing that
+ // prior to changing the size allows us to still have smooth animations.
+ int saved_icon_count =
+ prefs_->GetInteger(extensions::pref_names::kToolbarSize);
+ if (saved_icon_count != visible_icon_count_)
+ SetVisibleIconCount(saved_icon_count);
+ }
+}
+
+bool ToolbarActionsModel::RedesignIsShowingNewIcons() const {
+ for (const ToolbarItem& action : toolbar_items_) {
+ if (action.type == EXTENSION_ACTION) {
+ // Without the redesign, we only show extensions with browser actions.
+ // Any extension without a browser action is an indication that we're
+ // showing something new.
+ if (!GetExtensionById(action.id)->manifest()->HasKey(
+ extensions::manifest_keys::kBrowserAction))
+ return true;
+ }
+ }
+ return false;
+}
+
+const extensions::Extension* ToolbarActionsModel::GetExtensionById(
+ const std::string& id) const {
+ return extension_registry_->enabled_extensions().GetByID(id);
+}
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
new file mode 100644
index 0000000..d397f29
--- /dev/null
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -0,0 +1,311 @@
+// 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_TOOLBAR_TOOLBAR_ACTIONS_MODEL_H_
+#define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_MODEL_H_
+
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/extension_action.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry_observer.h"
+#include "extensions/common/extension.h"
+
+class Browser;
+class PrefService;
+class Profile;
+class ToolbarActionsBar;
+class ToolbarActionViewController;
+
+namespace extensions {
+class ExtensionRegistry;
+class ExtensionSet;
+}
+
+// Model for the browser actions toolbar.
+class ToolbarActionsModel : public extensions::ExtensionActionAPI::Observer,
+ public extensions::ExtensionRegistryObserver,
+ public KeyedService {
+ public:
+ // The different options for highlighting.
+ enum HighlightType {
+ HIGHLIGHT_NONE,
+ HIGHLIGHT_INFO,
+ HIGHLIGHT_WARNING,
+ };
+
+ // The different types of actions.
+ enum ActionType {
+ COMPONENT_ACTION,
+ EXTENSION_ACTION,
+ };
+
+ // An action id and its corresponding ActionType.
+ struct ToolbarItem {
+ ToolbarItem() {}
+ ToolbarItem(std::string action_id, ActionType action_type)
+ : id(action_id), type(action_type) {}
+
+ bool operator==(const ToolbarItem& other) { return other.id == id; }
+
+ std::string id;
+ ActionType type;
+ };
+
+ ToolbarActionsModel(Profile* profile,
+ extensions::ExtensionPrefs* extension_prefs);
+ ~ToolbarActionsModel() override;
+
+ // A class which is informed of changes to the model; represents the view of
+ // MVC. Also used for signaling view changes such as showing extension popups.
+ // TODO(devlin): Should this really be an observer? It acts more like a
+ // delegate.
+ class Observer {
+ public:
+ // Signals that an action with |id| has been added to the toolbar at
+ // |index|. This will *only* be called after the toolbar model has been
+ // initialized.
+ virtual void OnToolbarActionAdded(const std::string& id, int index) = 0;
+
+ // Signals that the given action with |id| has been removed from the
+ // toolbar.
+ virtual void OnToolbarActionRemoved(const std::string& id) = 0;
+
+ // Signals that the given action with |id| has been moved to |index|.
+ // |index| is the desired *final* index of the action (that is, in the
+ // adjusted order, action should be at |index|).
+ virtual void OnToolbarActionMoved(const std::string& id, int index) = 0;
+
+ // Signals that the browser action with |id| has been updated.
+ virtual void OnToolbarActionUpdated(const std::string& id) = 0;
+
+ // Signals the action with |id| to show the popup now in the active
+ // window. If |grant_active_tab| is true, then active tab permissions
+ // should be given to the action (only do this if this is through a user
+ // action). Returns true if a popup was slated to be shown.
+ virtual bool ShowToolbarActionPopup(const std::string& id,
+ bool grant_active_tab) = 0;
+
+ // Signals when the container needs to be redrawn because of a size change,
+ // and when the model has finished loading.
+ virtual void OnToolbarVisibleCountChanged() = 0;
+
+ // Signals that the model has entered or exited highlighting mode, or that
+ // the actions being highlighted have (probably*) changed. Highlighting
+ // mode indicates that only a subset of the toolbar actions are actively
+ // displayed, and those actions should be highlighted for extra emphasis.
+ // * probably, because if we are in highlight mode and receive a call to
+ // highlight a new set of actions, we do not compare the current set with
+ // the new set (and just assume the new set is different).
+ virtual void OnToolbarHighlightModeChanged(bool is_highlighting) = 0;
+
+ // Signals that the toolbar model has been initialized, so that if any
+ // observers were postponing animation during the initialization stage, they
+ // can catch up.
+ virtual void OnToolbarModelInitialized() = 0;
+
+ // Returns the browser associated with the Observer.
+ virtual Browser* GetBrowser() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ // Convenience function to get the ToolbarActionsModel for a Profile.
+ static ToolbarActionsModel* Get(Profile* profile);
+
+ // Adds or removes an observer.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Moves the given action with |id|'s icon to the given |index|.
+ void MoveActionIcon(const std::string& id, size_t index);
+
+ // Sets the number of action icons that should be visible.
+ // If count == size(), this will set the visible icon count to -1, meaning
+ // "show all actions".
+ void SetVisibleIconCount(size_t count);
+
+ size_t visible_icon_count() const {
+ // We have guards around this because |visible_icon_count_| can be set by
+ // prefs/sync, and we want to ensure that the icon count returned is within
+ // bounds.
+ return visible_icon_count_ == -1
+ ? toolbar_items().size()
+ : std::min(static_cast<size_t>(visible_icon_count_),
+ toolbar_items().size());
+ }
+
+ bool all_icons_visible() const { return visible_icon_count_ == -1; }
+
+ bool actions_initialized() const { return actions_initialized_; }
+
+ ScopedVector<ToolbarActionViewController> CreateActions(
+ Browser* browser,
+ ToolbarActionsBar* bar);
+
+ const std::vector<ToolbarItem>& toolbar_items() const {
+ return is_highlighting() ? highlighted_items_ : toolbar_items_;
+ }
+
+ bool is_highlighting() const { return highlight_type_ != HIGHLIGHT_NONE; }
+ HighlightType highlight_type() const { return highlight_type_; }
+
+ void OnActionToolbarPrefChange();
+
+ // Returns the index of the given action with |id|, or -1 if the id
+ // wasn't found.
+ int GetIndexForId(const std::string& id) const;
+
+ // Finds the Observer associated with |browser| and tells it to display a
+ // popup for the given action with |id|. If |grant_active_tab| is true,
+ // this grants active tab permissions to the action; only do this because of
+ // a direct user action.
+ bool ShowToolbarActionPopup(const std::string& id,
+ Browser* browser,
+ bool grant_active_tab);
+
+ // Ensures that the actions in the |action_ids| list are visible on the
+ // toolbar. This might mean they need to be moved to the front (if they are in
+ // the overflow bucket).
+ void EnsureVisibility(const std::vector<std::string>& action_ids);
+
+ // Highlights the actions specified by |action_ids|. This will cause
+ // the ToolbarModel to only display those actions.
+ // Highlighting mode is only entered if there is at least one action to be
+ // shown.
+ // Returns true if highlighting mode is entered, false otherwise.
+ bool HighlightActions(const std::vector<std::string>& action_ids,
+ HighlightType type);
+
+ // Stop highlighting actions. All actions can be shown again, and the
+ // number of visible icons will be reset to what it was before highlighting.
+ void StopHighlighting();
+
+ // Returns true if the toolbar model is running with the redesign and is
+ // showing new icons as a result.
+ bool RedesignIsShowingNewIcons() const;
+
+ private:
+ // Callback when actions are ready.
+ void OnReady();
+
+ // ExtensionRegistryObserver:
+ void OnExtensionLoaded(content::BrowserContext* browser_context,
+ const extensions::Extension* extension) override;
+ void OnExtensionUnloaded(
+ content::BrowserContext* browser_context,
+ const extensions::Extension* extension,
+ extensions::UnloadedExtensionInfo::Reason reason) override;
+ void OnExtensionUninstalled(content::BrowserContext* browser_context,
+ const extensions::Extension* extension,
+ extensions::UninstallReason reason) override;
+
+ // ExtensionActionAPI::Observer:
+ void OnExtensionActionUpdated(
+ ExtensionAction* extension_action,
+ content::WebContents* web_contents,
+ content::BrowserContext* browser_context) override;
+ void OnExtensionActionVisibilityChanged(const std::string& extension_id,
+ bool is_now_visible) override;
+
+ // To be called after the extension service is ready; gets loaded extensions
+ // from the ExtensionRegistry and their saved order from the pref service
+ // and constructs |toolbar_items_| from these data. IncognitoPopulate()
+ // takes the shortcut - looking at the regular model's content and modifying
+ // it.
+ void InitializeActionList();
+ void Populate(std::vector<std::string>* positions);
+ void IncognitoPopulate();
+
+ // Save the model to prefs.
+ void UpdatePrefs();
+
+ // Updates action with |action|'s id's browser action visibility pref if the
+ // browser action is in the overflow menu and should be considered hidden.
+ void MaybeUpdateVisibilityPref(const ToolbarItem& action, size_t index);
+
+ // Calls MaybeUpdateVisibilityPref() for each action in |toolbar_items|.
+ void MaybeUpdateVisibilityPrefs();
+
+ // Finds the last known visible position of the icon for |action|. The value
+ // returned is a zero-based index into the vector of visible items.
+ size_t FindNewPositionFromLastKnownGood(const ToolbarItem& action);
+
+ // Returns true if the given |extension| should be added to the toolbar.
+ bool ShouldAddExtension(const extensions::Extension* extension);
+
+ // Adds or removes the given |extension| from the toolbar model.
+ void AddExtension(const extensions::Extension* extension);
+ void RemoveExtension(const extensions::Extension* extension);
+
+ // Looks up and returns the extension with the given |id| in the set of
+ // enabled extensions.
+ const extensions::Extension* GetExtensionById(const std::string& id) const;
+
+ // Our observers.
+ base::ObserverList<Observer> observers_;
+
+ // The Profile this toolbar model is for.
+ Profile* profile_;
+
+ extensions::ExtensionPrefs* extension_prefs_;
+ PrefService* prefs_;
+
+ // The ExtensionActionAPI object, cached for convenience.
+ extensions::ExtensionActionAPI* extension_action_api_;
+
+ // The ExtensionRegistry object, cached for convenience.
+ extensions::ExtensionRegistry* extension_registry_;
+
+ // True if we've handled the initial EXTENSIONS_READY notification.
+ bool actions_initialized_;
+
+ // If true, we include all actions in the toolbar model.
+ bool use_redesign_;
+
+ // Ordered list of browser actions.
+ std::vector<ToolbarItem> toolbar_items_;
+
+ // List of browser actions which should be highlighted.
+ std::vector<ToolbarItem> highlighted_items_;
+
+ // The current type of highlight (with HIGHLIGHT_NONE indicating no current
+ // highlight).
+ HighlightType highlight_type_;
+
+ // A list of action ids ordered to correspond with their last known
+ // positions.
+ std::vector<std::string> last_known_positions_;
+
+ // The number of icons visible (the rest should be hidden in the overflow
+ // chevron). A value of -1 indicates that all icons should be visible.
+ // Instead of using this variable directly, use visible_icon_count() if
+ // possible.
+ // TODO(devlin): Make a new variable to indicate that all icons should be
+ // visible, instead of overloading this one.
+ int visible_icon_count_;
+
+ ScopedObserver<extensions::ExtensionActionAPI,
+ extensions::ExtensionActionAPI::Observer>
+ extension_action_observer_;
+
+ // Listen to extension load, unloaded notifications.
+ ScopedObserver<extensions::ExtensionRegistry, ExtensionRegistryObserver>
+ extension_registry_observer_;
+
+ // For observing change of toolbar order preference by external entity (sync).
+ PrefChangeRegistrar pref_change_registrar_;
+ base::Closure pref_change_callback_;
+
+ base::WeakPtrFactory<ToolbarActionsModel> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToolbarActionsModel);
+};
+
+#endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_MODEL_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc
new file mode 100644
index 0000000..b6e80ee
--- /dev/null
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_factory.cc
@@ -0,0 +1,55 @@
+// Copyright 2013 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/toolbar/toolbar_actions_model_factory.h"
+
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extensions_browser_client.h"
+
+// static
+ToolbarActionsModel* ToolbarActionsModelFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<ToolbarActionsModel*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+ToolbarActionsModelFactory* ToolbarActionsModelFactory::GetInstance() {
+ return Singleton<ToolbarActionsModelFactory>::get();
+}
+
+ToolbarActionsModelFactory::ToolbarActionsModelFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ToolbarActionsModel",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
+ DependsOn(extensions::ExtensionActionAPI::GetFactoryInstance());
+}
+
+ToolbarActionsModelFactory::~ToolbarActionsModelFactory() {}
+
+KeyedService* ToolbarActionsModelFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ToolbarActionsModel(
+ Profile::FromBrowserContext(context),
+ extensions::ExtensionPrefsFactory::GetForBrowserContext(context));
+}
+
+content::BrowserContext* ToolbarActionsModelFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return context;
+}
+
+bool ToolbarActionsModelFactory::ServiceIsCreatedWithBrowserContext() const {
+ return true;
+}
+
+bool ToolbarActionsModelFactory::ServiceIsNULLWhileTesting() const {
+ return true;
+}
diff --git a/chrome/browser/extensions/extension_toolbar_model_factory.h b/chrome/browser/ui/toolbar/toolbar_actions_model_factory.h
index 6b5c77f..cc89475 100644
--- a/chrome/browser/extensions/extension_toolbar_model_factory.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_factory.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_FACTORY_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_FACTORY_H_
+#ifndef CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_MODEL_FACTORY_H_
+#define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_MODEL_FACTORY_H_
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
@@ -11,21 +11,19 @@
class Profile;
-namespace extensions {
+class ToolbarActionsModel;
-class ExtensionToolbarModel;
-
-class ExtensionToolbarModelFactory : public BrowserContextKeyedServiceFactory {
+class ToolbarActionsModelFactory : public BrowserContextKeyedServiceFactory {
public:
- static ExtensionToolbarModel* GetForProfile(Profile* profile);
+ static ToolbarActionsModel* GetForProfile(Profile* profile);
- static ExtensionToolbarModelFactory* GetInstance();
+ static ToolbarActionsModelFactory* GetInstance();
private:
- friend struct DefaultSingletonTraits<ExtensionToolbarModelFactory>;
+ friend struct DefaultSingletonTraits<ToolbarActionsModelFactory>;
- ExtensionToolbarModelFactory();
- ~ExtensionToolbarModelFactory() override;
+ ToolbarActionsModelFactory();
+ ~ToolbarActionsModelFactory() override;
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const override;
@@ -35,6 +33,4 @@ class ExtensionToolbarModelFactory : public BrowserContextKeyedServiceFactory {
bool ServiceIsNULLWhileTesting() const override;
};
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_FACTORY_H_
+#endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_MODEL_FACTORY_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
new file mode 100644
index 0000000..0f0338c
--- /dev/null
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -0,0 +1,1369 @@
+// Copyright 2014 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 "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/extension_action_manager.h"
+#include "chrome/browser/extensions/extension_action_test_util.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/test_extension_dir.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
+#include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
+#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
+#include "chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h"
+#include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "components/crx_file/id_util.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/pref_names.h"
+#include "extensions/browser/test_extension_registry_observer.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/value_builder.h"
+
+namespace {
+
+// A simple observer that tracks the number of times certain events occur.
+class ToolbarActionsModelTestObserver : public ToolbarActionsModel::Observer {
+ public:
+ explicit ToolbarActionsModelTestObserver(ToolbarActionsModel* model);
+ ~ToolbarActionsModelTestObserver() override;
+
+ size_t inserted_count() const { return inserted_count_; }
+ size_t removed_count() const { return removed_count_; }
+ size_t moved_count() const { return moved_count_; }
+ int highlight_mode_count() const { return highlight_mode_count_; }
+ size_t initialized_count() const { return initialized_count_; }
+
+ private:
+ // ToolbarActionsModel::Observer:
+ void OnToolbarActionAdded(const std::string& id, int index) override {
+ ++inserted_count_;
+ }
+
+ void OnToolbarActionRemoved(const std::string& id) override {
+ ++removed_count_;
+ }
+
+ void OnToolbarActionMoved(const std::string& id, int index) override {
+ ++moved_count_;
+ }
+
+ void OnToolbarActionUpdated(const std::string& id) override {}
+
+ bool ShowToolbarActionPopup(const std::string& id,
+ bool grant_active_tab) override {
+ return false;
+ }
+
+ void OnToolbarVisibleCountChanged() override {}
+
+ void OnToolbarHighlightModeChanged(bool is_highlighting) override {
+ // Add one if highlighting, subtract one if not.
+ highlight_mode_count_ += is_highlighting ? 1 : -1;
+ }
+
+ void OnToolbarModelInitialized() override { ++initialized_count_; }
+
+ Browser* GetBrowser() override { return NULL; }
+
+ ToolbarActionsModel* model_;
+
+ size_t inserted_count_;
+ size_t removed_count_;
+ size_t moved_count_;
+ // Int because it could become negative (if something goes wrong).
+ int highlight_mode_count_;
+ size_t initialized_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToolbarActionsModelTestObserver);
+};
+
+ToolbarActionsModelTestObserver::ToolbarActionsModelTestObserver(
+ ToolbarActionsModel* model)
+ : model_(model),
+ inserted_count_(0),
+ removed_count_(0),
+ moved_count_(0),
+ highlight_mode_count_(0),
+ initialized_count_(0) {
+ model_->AddObserver(this);
+}
+
+ToolbarActionsModelTestObserver::~ToolbarActionsModelTestObserver() {
+ model_->RemoveObserver(this);
+}
+
+} // namespace
+
+class ToolbarActionsModelUnitTest
+ : public extensions::ExtensionServiceTestBase {
+ public:
+ ToolbarActionsModelUnitTest(){};
+ ~ToolbarActionsModelUnitTest() override{};
+
+ protected:
+ // Initialize the ExtensionService, ToolbarActionsModel, and
+ // ExtensionSystem.
+ void Init();
+
+ void TearDown() override;
+
+ // Adds or removes the given |extension| and verify success.
+ testing::AssertionResult AddExtension(
+ const scoped_refptr<const extensions::Extension>& extension)
+ WARN_UNUSED_RESULT;
+ testing::AssertionResult RemoveExtension(
+ const scoped_refptr<const extensions::Extension>& extension)
+ WARN_UNUSED_RESULT;
+
+ // Adds three extensions, all with browser actions.
+ testing::AssertionResult AddBrowserActionExtensions() WARN_UNUSED_RESULT;
+
+ // Adds three extensions, one each for browser action, page action, and no
+ // action, and are added in that order.
+ testing::AssertionResult AddActionExtensions() WARN_UNUSED_RESULT;
+
+ // Returns the action's id at the given index in the toolbar model, or empty
+ // if one does not exist.
+ // If |model| is specified, it is used. Otherwise, this defaults to
+ // |toolbar_model_|.
+ const std::string GetActionIdAtIndex(size_t index,
+ const ToolbarActionsModel* model) const;
+ const std::string GetActionIdAtIndex(size_t index) const;
+
+ void SetMockActionsFactory(MockComponentToolbarActionsFactory* factory);
+
+ ToolbarActionsModel* toolbar_model() { return toolbar_model_; }
+
+ const ToolbarActionsModelTestObserver* observer() const {
+ return model_observer_.get();
+ }
+ size_t num_toolbar_items() const {
+ return toolbar_model_->toolbar_items().size();
+ }
+ const extensions::Extension* browser_action_a() const {
+ return browser_action_a_.get();
+ }
+ const extensions::Extension* browser_action_b() const {
+ return browser_action_b_.get();
+ }
+ const extensions::Extension* browser_action_c() const {
+ return browser_action_c_.get();
+ }
+ const extensions::Extension* browser_action() const {
+ return browser_action_extension_.get();
+ }
+ const extensions::Extension* page_action() const {
+ return page_action_extension_.get();
+ }
+ const extensions::Extension* no_action() const {
+ return no_action_extension_.get();
+ }
+
+ // The mock component action will be referred to as "MCA" below.
+ const char* component_action_id() {
+ return ComponentToolbarActionsFactory::kActionIdForTesting;
+ }
+
+ private:
+ // Verifies that all extensions in |extensions| are added successfully.
+ testing::AssertionResult AddAndVerifyExtensions(
+ const extensions::ExtensionList& extensions);
+
+ // The toolbar model associated with the testing profile.
+ ToolbarActionsModel* toolbar_model_;
+
+ // The test observer to track events. Must come after toolbar_model_ so that
+ // it is destroyed and removes itself as an observer first.
+ scoped_ptr<ToolbarActionsModelTestObserver> model_observer_;
+
+ // Sample extensions with only browser actions.
+ scoped_refptr<const extensions::Extension> browser_action_a_;
+ scoped_refptr<const extensions::Extension> browser_action_b_;
+ scoped_refptr<const extensions::Extension> browser_action_c_;
+
+ // Sample extensions with different kinds of actions.
+ scoped_refptr<const extensions::Extension> browser_action_extension_;
+ scoped_refptr<const extensions::Extension> page_action_extension_;
+ scoped_refptr<const extensions::Extension> no_action_extension_;
+
+ scoped_ptr<MockComponentToolbarActionsFactory> mock_actions_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToolbarActionsModelUnitTest);
+};
+
+void ToolbarActionsModelUnitTest::Init() {
+ InitializeEmptyExtensionService();
+ toolbar_model_ =
+ extensions::extension_action_test_util::CreateToolbarModelForProfile(
+ profile());
+ model_observer_.reset(new ToolbarActionsModelTestObserver(toolbar_model_));
+}
+
+void ToolbarActionsModelUnitTest::TearDown() {
+ model_observer_.reset();
+ extensions::ExtensionServiceTestBase::TearDown();
+}
+
+testing::AssertionResult ToolbarActionsModelUnitTest::AddExtension(
+ const scoped_refptr<const extensions::Extension>& extension) {
+ if (registry()->enabled_extensions().GetByID(extension->id())) {
+ return testing::AssertionFailure() << "Extension " << extension->name()
+ << " already installed!";
+ }
+ service()->AddExtension(extension.get());
+ if (!registry()->enabled_extensions().GetByID(extension->id())) {
+ return testing::AssertionFailure() << "Failed to install extension: "
+ << extension->name();
+ }
+ return testing::AssertionSuccess();
+}
+
+testing::AssertionResult ToolbarActionsModelUnitTest::RemoveExtension(
+ const scoped_refptr<const extensions::Extension>& extension) {
+ if (!registry()->enabled_extensions().GetByID(extension->id())) {
+ return testing::AssertionFailure() << "Extension " << extension->name()
+ << " not installed!";
+ }
+ service()->UnloadExtension(extension->id(),
+ extensions::UnloadedExtensionInfo::REASON_DISABLE);
+ if (registry()->enabled_extensions().GetByID(extension->id())) {
+ return testing::AssertionFailure() << "Failed to unload extension: "
+ << extension->name();
+ }
+ return testing::AssertionSuccess();
+}
+
+testing::AssertionResult ToolbarActionsModelUnitTest::AddActionExtensions() {
+ browser_action_extension_ =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "browser_action",
+ extensions::extension_action_test_util::BROWSER_ACTION);
+ page_action_extension_ =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "page_action", extensions::extension_action_test_util::PAGE_ACTION);
+ no_action_extension_ =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "no_action", extensions::extension_action_test_util::NO_ACTION);
+
+ extensions::ExtensionList extensions;
+ extensions.push_back(browser_action_extension_);
+ extensions.push_back(page_action_extension_);
+ extensions.push_back(no_action_extension_);
+
+ return AddAndVerifyExtensions(extensions);
+}
+
+testing::AssertionResult
+ToolbarActionsModelUnitTest::AddBrowserActionExtensions() {
+ browser_action_a_ =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "browser_actionA",
+ extensions::extension_action_test_util::BROWSER_ACTION);
+ browser_action_b_ =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "browser_actionB",
+ extensions::extension_action_test_util::BROWSER_ACTION);
+ browser_action_c_ =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "browser_actionC",
+ extensions::extension_action_test_util::BROWSER_ACTION);
+
+ extensions::ExtensionList extensions;
+ extensions.push_back(browser_action_a_);
+ extensions.push_back(browser_action_b_);
+ extensions.push_back(browser_action_c_);
+
+ return AddAndVerifyExtensions(extensions);
+}
+
+const std::string ToolbarActionsModelUnitTest::GetActionIdAtIndex(
+ size_t index,
+ const ToolbarActionsModel* model) const {
+ return index < model->toolbar_items().size()
+ ? model->toolbar_items()[index].id
+ : std::string();
+}
+
+const std::string ToolbarActionsModelUnitTest::GetActionIdAtIndex(
+ size_t index) const {
+ return GetActionIdAtIndex(index, toolbar_model_);
+}
+
+testing::AssertionResult ToolbarActionsModelUnitTest::AddAndVerifyExtensions(
+ const extensions::ExtensionList& extensions) {
+ for (extensions::ExtensionList::const_iterator iter = extensions.begin();
+ iter != extensions.end(); ++iter) {
+ if (!AddExtension(*iter)) {
+ return testing::AssertionFailure() << "Failed to install extension: "
+ << (*iter)->name();
+ }
+ }
+ return testing::AssertionSuccess();
+}
+
+void ToolbarActionsModelUnitTest::SetMockActionsFactory(
+ MockComponentToolbarActionsFactory* factory) {
+ mock_actions_factory_.reset(factory);
+}
+
+// A basic test for component actions and extensions with browser actions
+// showing up in the toolbar.
+TEST_F(ToolbarActionsModelUnitTest, BasicToolbarActionsModelTest) {
+ Init();
+
+ // Load an extension with no browser action.
+ scoped_refptr<const extensions::Extension> extension1 =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "no_action", extensions::extension_action_test_util::NO_ACTION);
+ ASSERT_TRUE(AddExtension(extension1));
+
+ // This extension should not be in the model (has no browser action).
+ EXPECT_EQ(0u, observer()->inserted_count());
+ EXPECT_EQ(0u, num_toolbar_items());
+ EXPECT_EQ(std::string(), GetActionIdAtIndex(0u));
+
+ // Load an extension with a browser action.
+ scoped_refptr<const extensions::Extension> extension2 =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "browser_action",
+ extensions::extension_action_test_util::BROWSER_ACTION);
+ ASSERT_TRUE(AddExtension(extension2));
+
+ // We should now find our extension in the model.
+ EXPECT_EQ(1u, observer()->inserted_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(extension2->id(), GetActionIdAtIndex(0u));
+
+ // Should be a no-op, but still fires the events.
+ toolbar_model()->MoveActionIcon(extension2->id(), 0);
+ EXPECT_EQ(1u, observer()->moved_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(extension2->id(), GetActionIdAtIndex(0u));
+
+ // Remove the extension and verify.
+ ASSERT_TRUE(RemoveExtension(extension2));
+ EXPECT_EQ(1u, observer()->removed_count());
+ EXPECT_EQ(0u, num_toolbar_items());
+ EXPECT_EQ(std::string(), GetActionIdAtIndex(0u));
+}
+
+// Test various different reorderings, removals, and reinsertions.
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarReorderAndReinsert) {
+ Init();
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+
+ // Verify the three actions are in the model in the proper order.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+
+ // Order is now A, B, C. Let's put C first.
+ toolbar_model()->MoveActionIcon(browser_action_c()->id(), 0);
+ EXPECT_EQ(1u, observer()->moved_count());
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+
+ // Order is now C, A, B. Let's put A last.
+ toolbar_model()->MoveActionIcon(browser_action_a()->id(), 2);
+ EXPECT_EQ(2u, observer()->moved_count());
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2u));
+
+ // Order is now C, B, A. Let's remove B.
+ ASSERT_TRUE(RemoveExtension(browser_action_b()));
+ EXPECT_EQ(1u, observer()->removed_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
+
+ // Load extension B again.
+ ASSERT_TRUE(AddExtension(browser_action_b()));
+
+ // Extension B loaded again.
+ EXPECT_EQ(4u, observer()->inserted_count());
+ EXPECT_EQ(3u, num_toolbar_items());
+ // Make sure it gets its old spot in the list.
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+
+ // Unload B again.
+ ASSERT_TRUE(RemoveExtension(browser_action_b()));
+ EXPECT_EQ(2u, observer()->removed_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+
+ // Order is now C, A. Flip it.
+ toolbar_model()->MoveActionIcon(browser_action_a()->id(), 0);
+ EXPECT_EQ(3u, observer()->moved_count());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+
+ // Move A to the location it already occupies.
+ toolbar_model()->MoveActionIcon(browser_action_a()->id(), 0);
+ EXPECT_EQ(4u, observer()->moved_count());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+
+ // Order is now A, C.
+ ASSERT_TRUE(RemoveExtension(browser_action_c()));
+ EXPECT_EQ(3u, observer()->removed_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+
+ // Load extension C again.
+ ASSERT_TRUE(AddExtension(browser_action_c()));
+
+ // Extension C loaded again.
+ EXPECT_EQ(5u, observer()->inserted_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+ // Make sure it gets its old spot in the list (at the very end).
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+}
+
+// Test that order persists after unloading and disabling, but not across
+// uninstallation.
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarUnloadDisableAndUninstall) {
+ Init();
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+
+ // Verify the three actions are in the model in the proper order: A, B, C.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+
+ // Unload B, then C, then A, and then reload C, then A, then B.
+ ASSERT_TRUE(RemoveExtension(browser_action_b()));
+ ASSERT_TRUE(RemoveExtension(browser_action_c()));
+ ASSERT_TRUE(RemoveExtension(browser_action_a()));
+ EXPECT_EQ(0u, num_toolbar_items()); // Sanity check: all gone?
+ ASSERT_TRUE(AddExtension(browser_action_c()));
+ ASSERT_TRUE(AddExtension(browser_action_a()));
+ ASSERT_TRUE(AddExtension(browser_action_b()));
+ EXPECT_EQ(3u, num_toolbar_items()); // Sanity check: all back?
+ EXPECT_EQ(0u, observer()->moved_count());
+
+ // Even though we unloaded and reloaded in a different order, the original
+ // order (A, B, C) should be preserved.
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+
+ // Disabling extensions should also preserve order.
+ service()->DisableExtension(browser_action_b()->id(),
+ extensions::Extension::DISABLE_USER_ACTION);
+ service()->DisableExtension(browser_action_c()->id(),
+ extensions::Extension::DISABLE_USER_ACTION);
+ service()->DisableExtension(browser_action_a()->id(),
+ extensions::Extension::DISABLE_USER_ACTION);
+ service()->EnableExtension(browser_action_c()->id());
+ service()->EnableExtension(browser_action_a()->id());
+ service()->EnableExtension(browser_action_b()->id());
+
+ // Make sure we still get the original A, B, C order.
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+
+ // Move browser_action_b() to be first.
+ toolbar_model()->MoveActionIcon(browser_action_b()->id(), 0);
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
+
+ // Uninstall Extension B.
+ service()->UninstallExtension(browser_action_b()->id(),
+ extensions::UNINSTALL_REASON_FOR_TESTING,
+ base::Bind(&base::DoNothing),
+ NULL); // Ignore error.
+ // List contains only A and C now. Validate that.
+ EXPECT_EQ(2u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+
+ ASSERT_TRUE(AddExtension(browser_action_b()));
+
+ // Make sure Extension B is _not_ first (its old position should have been
+ // forgotten at uninstall time). Order should be A, C, B.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ReorderOnPrefChange) {
+ Init();
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+ EXPECT_EQ(3u, num_toolbar_items());
+
+ // Change the value of the toolbar preference.
+ std::vector<std::string> new_order;
+ new_order.push_back(browser_action_c()->id());
+ new_order.push_back(browser_action_b()->id());
+ extensions::ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order);
+
+ // Verify order is changed.
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2u));
+}
+
+// Test that new extension actions are always visible on installation and
+// inserted at the "end" of the visible section.
+TEST_F(ToolbarActionsModelUnitTest, NewToolbarExtensionsAreVisible) {
+ Init();
+
+ // Three extensions with actions.
+ scoped_refptr<const extensions::Extension> extension_a =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "a", extensions::extension_action_test_util::BROWSER_ACTION);
+ scoped_refptr<const extensions::Extension> extension_b =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "b", extensions::extension_action_test_util::BROWSER_ACTION);
+ scoped_refptr<const extensions::Extension> extension_c =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "c", extensions::extension_action_test_util::BROWSER_ACTION);
+ scoped_refptr<const extensions::Extension> extension_d =
+ extensions::extension_action_test_util::CreateActionExtension(
+ "d", extensions::extension_action_test_util::BROWSER_ACTION);
+
+ // We should start off without any actions.
+ EXPECT_EQ(0u, num_toolbar_items());
+ EXPECT_EQ(0u, toolbar_model()->visible_icon_count());
+
+ // Add one action. It should be visible.
+ service()->AddExtension(extension_a.get());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(extension_a.get()->id(), GetActionIdAtIndex(0u));
+
+ // Hide all actions.
+ toolbar_model()->SetVisibleIconCount(0);
+ EXPECT_EQ(0u, toolbar_model()->visible_icon_count());
+
+ // Add a new action - it should be visible, so it should be in the first
+ // index. The other action should remain hidden.
+ service()->AddExtension(extension_b.get());
+ EXPECT_EQ(2u, num_toolbar_items());
+ EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(extension_b.get()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_a.get()->id(), GetActionIdAtIndex(1u));
+
+ // Show all actions.
+ toolbar_model()->SetVisibleIconCount(2);
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+
+ // Add the third action. Since all action are visible, it should go in the
+ // last index.
+ service()->AddExtension(extension_c.get());
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+ EXPECT_EQ(extension_b.get()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_a.get()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_c.get()->id(), GetActionIdAtIndex(2u));
+
+ // Hide one action (two remaining visible).
+ toolbar_model()->SetVisibleIconCount(2);
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+
+ // Add a fourth action. It should go at the end of the visible section and
+ // be visible, so it increases visible count by 1, and goes into the fourth
+ // index. The hidden action should remain hidden.
+ service()->AddExtension(extension_d.get());
+ EXPECT_EQ(4u, num_toolbar_items());
+ EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(extension_b.get()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_a.get()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_d.get()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(extension_c.get()->id(), GetActionIdAtIndex(3u));
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarHighlightMode) {
+ Init();
+
+ EXPECT_FALSE(toolbar_model()->HighlightActions(
+ std::vector<std::string>(), ToolbarActionsModel::HIGHLIGHT_WARNING));
+ EXPECT_EQ(0, observer()->highlight_mode_count());
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+ EXPECT_EQ(3u, num_toolbar_items());
+
+ // Start with a visible count of 2 (non-zero, and not all).
+ toolbar_model()->SetVisibleIconCount(2u);
+
+ // Highlight one extension.
+ std::vector<std::string> action_ids;
+ action_ids.push_back(browser_action_b()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_EQ(1, observer()->highlight_mode_count());
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
+
+ // Stop highlighting.
+ toolbar_model()->StopHighlighting();
+ EXPECT_EQ(0, observer()->highlight_mode_count());
+ EXPECT_FALSE(toolbar_model()->is_highlighting());
+
+ // Verify that the extensions are back to normal.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+
+ // Call stop highlighting a second time (shouldn't be notified).
+ toolbar_model()->StopHighlighting();
+ EXPECT_EQ(0, observer()->highlight_mode_count());
+ EXPECT_FALSE(toolbar_model()->is_highlighting());
+
+ // Highlight all extensions.
+ action_ids.clear();
+ action_ids.push_back(browser_action_a()->id());
+ action_ids.push_back(browser_action_b()->id());
+ action_ids.push_back(browser_action_c()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_EQ(1, observer()->highlight_mode_count());
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
+ // Even though the visible count is 3, we shouldn't adjust the stored
+ // preference.
+ EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(
+ extensions::pref_names::kToolbarSize));
+
+ // Highlight only extension B (shrink the highlight list).
+ action_ids.clear();
+ action_ids.push_back(browser_action_b()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_EQ(2, observer()->highlight_mode_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
+
+ // Highlight extensions A and B (grow the highlight list).
+ action_ids.clear();
+ action_ids.push_back(browser_action_a()->id());
+ action_ids.push_back(browser_action_b()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_EQ(3, observer()->highlight_mode_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+
+ // Highlight no extensions (empty the highlight list).
+ action_ids.clear();
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_EQ(2, observer()->highlight_mode_count());
+ EXPECT_FALSE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+ // Our toolbar size should be back to normal.
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(
+ extensions::pref_names::kToolbarSize));
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarHighlightModeRemove) {
+ Init();
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+ EXPECT_EQ(3u, num_toolbar_items());
+
+ // Highlight two of the extensions.
+ std::vector<std::string> action_ids;
+ action_ids.push_back(browser_action_a()->id());
+ action_ids.push_back(browser_action_b()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1, observer()->highlight_mode_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+
+ // Disable one of them - only one should remain highlighted.
+ service()->DisableExtension(browser_action_a()->id(),
+ extensions::Extension::DISABLE_USER_ACTION);
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
+
+ // Uninstall the remaining highlighted extension. This should result in
+ // highlight mode exiting.
+ service()->UninstallExtension(browser_action_b()->id(),
+ extensions::UNINSTALL_REASON_FOR_TESTING,
+ base::Bind(&base::DoNothing),
+ NULL); // Ignore error.
+ EXPECT_FALSE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(0, observer()->highlight_mode_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+
+ // Test that removing an unhighlighted extension still works.
+ // Reinstall extension B, and then highlight extension C.
+ ASSERT_TRUE(AddExtension(browser_action_b()));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ action_ids.clear();
+ action_ids.push_back(browser_action_c()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_EQ(1, observer()->highlight_mode_count());
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+
+ // Uninstalling B should not have visible impact.
+ service()->UninstallExtension(browser_action_b()->id(),
+ extensions::UNINSTALL_REASON_FOR_TESTING,
+ base::Bind(&base::DoNothing),
+ NULL); // Ignore error.
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1, observer()->highlight_mode_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+
+ // When we stop, only action C should remain.
+ toolbar_model()->StopHighlighting();
+ EXPECT_FALSE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(0, observer()->highlight_mode_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarHighlightModeAdd) {
+ Init();
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+ EXPECT_EQ(3u, num_toolbar_items());
+
+ // Remove one (down to two).
+ ASSERT_TRUE(RemoveExtension(browser_action_c()));
+
+ // Highlight one of the two actions.
+ std::vector<std::string> action_ids;
+ action_ids.push_back(browser_action_a()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+
+ // Adding a new extension should have no visible effect.
+ ASSERT_TRUE(AddExtension(browser_action_c()));
+ EXPECT_TRUE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+
+ // When we stop highlighting, we should see the new extension show up.
+ toolbar_model()->StopHighlighting();
+ EXPECT_FALSE(toolbar_model()->is_highlighting());
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+}
+
+// Test that the action toolbar maintains the proper size, even after a pref
+// change.
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarSizeAfterPrefChange) {
+ Init();
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+ EXPECT_EQ(3u, num_toolbar_items());
+
+ // Should be at max size.
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+ EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count());
+ toolbar_model()->OnActionToolbarPrefChange();
+ // Should still be at max size.
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+ EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count());
+}
+
+// Test that, in the absence of the extension-action-redesign switch, the
+// model only contains extensions with browser actions and component actions.
+TEST_F(ToolbarActionsModelUnitTest, TestToolbarExtensionTypesNoSwitch) {
+ Init();
+ ASSERT_TRUE(AddActionExtensions());
+
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(browser_action()->id(), GetActionIdAtIndex(0u));
+}
+
+// Test that, with the extension-action-redesign switch, the model contains
+// all types of extensions, except those which should not be displayed on the
+// toolbar (like component extensions).
+TEST_F(ToolbarActionsModelUnitTest, TestToolbarExtensionTypesSwitch) {
+ extensions::FeatureSwitch::ScopedOverride enable_redesign(
+ extensions::FeatureSwitch::extension_action_redesign(), true);
+ Init();
+
+ ASSERT_TRUE(AddActionExtensions());
+
+ // With the switch on, extensions with page actions and no action should also
+ // be displayed in the toolbar.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(page_action()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(no_action()->id(), GetActionIdAtIndex(2u));
+}
+
+// Test that hiding actions on the toolbar results in their removal from the
+// model when the redesign switch is not enabled.
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarActionsVisibilityNoSwitch) {
+ Init();
+
+ extensions::ExtensionActionAPI* action_api =
+ extensions::ExtensionActionAPI::Get(profile());
+
+ ASSERT_TRUE(AddBrowserActionExtensions());
+ // Sanity check: Order should start as A , B, C.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+
+ // By default, all actions should be visible.
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_a()->id()));
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_b()->id()));
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_c()->id()));
+
+ // Hiding an action should result in its removal from the toolbar.
+ action_api->SetBrowserActionVisibility(browser_action_b()->id(), false);
+ EXPECT_FALSE(
+ action_api->GetBrowserActionVisibility(browser_action_b()->id()));
+ // Thus, there should now only be two items on the toolbar - A and C.
+ EXPECT_EQ(2u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+
+ // Resetting the visibility to 'true' should result in the extension being
+ // added back at its original position.
+ action_api->SetBrowserActionVisibility(browser_action_b()->id(), true);
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_b()->id()));
+ // So the toolbar order should be A, B, C.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarIncognitoModeTest) {
+ Init();
+ ASSERT_TRUE(AddBrowserActionExtensions());
+
+ // Give two extensions incognito access.
+ // Note: We use ExtensionPrefs::SetIsIncognitoEnabled instead of
+ // util::SetIsIncognitoEnabled because the latter tries to reload the
+ // extension, which requries a filepath associated with the extension (and,
+ // for this test, reloading the extension is irrelevant to us).
+ extensions::ExtensionPrefs* extension_prefs =
+ extensions::ExtensionPrefs::Get(profile());
+ extension_prefs->SetIsIncognitoEnabled(browser_action_b()->id(), true);
+ extension_prefs->SetIsIncognitoEnabled(browser_action_c()->id(), true);
+
+ extensions::util::SetIsIncognitoEnabled(browser_action_b()->id(), profile(),
+ true);
+ extensions::util::SetIsIncognitoEnabled(browser_action_c()->id(), profile(),
+ true);
+
+ // Move C to the second index.
+ toolbar_model()->MoveActionIcon(browser_action_c()->id(), 1u);
+ // Set visible count to 3 so that C is overflowed. State is A, C, [B].
+ toolbar_model()->SetVisibleIconCount(2);
+ EXPECT_EQ(1u, observer()->moved_count());
+
+ // Get an incognito profile and toolbar.
+ ToolbarActionsModel* incognito_model =
+ extensions::extension_action_test_util::CreateToolbarModelForProfile(
+ profile()->GetOffTheRecordProfile());
+
+ ToolbarActionsModelTestObserver incognito_observer(incognito_model);
+ EXPECT_EQ(0u, incognito_observer.moved_count());
+
+ // We should have two items: C, B, and the order should be preserved from the
+ // original model.
+ EXPECT_EQ(2u, incognito_model->toolbar_items().size());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u, incognito_model));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u, incognito_model));
+
+ // Actions in the overflow menu in the regular toolbar should remain in
+ // overflow in the incognito toolbar. So, we should have C, [B].
+ EXPECT_EQ(1u, incognito_model->visible_icon_count());
+ // The regular model should still have two icons visible.
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+
+ // Changing the incognito model size should not affect the regular model.
+ incognito_model->SetVisibleIconCount(0);
+ EXPECT_EQ(0u, incognito_model->visible_icon_count());
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+
+ // Expanding the incognito model to 3 should register as "all icons"
+ // since it is all of the incognito-enabled extensions.
+ incognito_model->SetVisibleIconCount(2u);
+ EXPECT_EQ(2u, incognito_model->visible_icon_count());
+ EXPECT_TRUE(incognito_model->all_icons_visible());
+
+ // Moving icons in the incognito toolbar should not affect the regular
+ // toolbar. Incognito currently has C, B...
+ incognito_model->MoveActionIcon(browser_action_b()->id(), 0u);
+ // So now it should be B, C...
+ EXPECT_EQ(1u, incognito_observer.moved_count());
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u, incognito_model));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u, incognito_model));
+ // ... and the regular toolbar should be unaffected.
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+
+ // Similarly, the observer for the regular model should not have received
+ // any updates.
+ EXPECT_EQ(1u, observer()->moved_count());
+
+ // And performing moves on the regular model should have no effect on the
+ // incognito model or its observers.
+ toolbar_model()->MoveActionIcon(browser_action_c()->id(), 2u);
+ EXPECT_EQ(2u, observer()->moved_count());
+ EXPECT_EQ(1u, incognito_observer.moved_count());
+}
+
+// Test that enabling extensions incognito with an active incognito profile
+// works.
+TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarIncognitoEnableExtension) {
+ Init();
+
+ const char* kManifest =
+ "{"
+ " \"name\": \"%s\","
+ " \"version\": \"1.0\","
+ " \"manifest_version\": 2,"
+ " \"browser_action\": {}"
+ "}";
+
+ // For this test, we need to have "real" extension files, because we need to
+ // be able to reload them during the incognito process. Since the toolbar
+ // needs to be notified of the reload, we need it this time (as opposed to
+ // above, where we simply set the prefs before the incognito bar was
+ // created.
+ extensions::TestExtensionDir dir1;
+ dir1.WriteManifest(base::StringPrintf(kManifest, "incognito1"));
+ extensions::TestExtensionDir dir2;
+ dir2.WriteManifest(base::StringPrintf(kManifest, "incognito2"));
+
+ extensions::TestExtensionDir* dirs[] = {&dir1, &dir2};
+ const extensions::Extension* extensions[] = {nullptr, nullptr};
+ for (size_t i = 0; i < arraysize(dirs); ++i) {
+ // The extension id will be calculated from the file path; we need this to
+ // wait for the extension to load.
+ base::FilePath path_for_id =
+ base::MakeAbsoluteFilePath(dirs[i]->unpacked_path());
+ std::string id = crx_file::id_util::GenerateIdForPath(path_for_id);
+ extensions::TestExtensionRegistryObserver observer(registry(), id);
+ extensions::UnpackedInstaller::Create(service())
+ ->Load(dirs[i]->unpacked_path());
+ observer.WaitForExtensionLoaded();
+ extensions[i] = registry()->enabled_extensions().GetByID(id);
+ ASSERT_TRUE(extensions[i]);
+ }
+
+ // For readability, alias to A and B. Since we'll be reloading these
+ // extensions, we also can't rely on pointers.
+ std::string extension_a = extensions[0]->id();
+ std::string extension_b = extensions[1]->id();
+
+ // The first model should have both extensions visible.
+ EXPECT_EQ(2u, toolbar_model()->toolbar_items().size());
+ EXPECT_EQ(extension_a, GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_b, GetActionIdAtIndex(1u));
+
+ // Set the model to only show one extension, so the order is A, [B].
+ toolbar_model()->SetVisibleIconCount(1u);
+
+ // Get an incognito profile and toolbar.
+ ToolbarActionsModel* incognito_model =
+ extensions::extension_action_test_util::CreateToolbarModelForProfile(
+ profile()->GetOffTheRecordProfile());
+ ToolbarActionsModelTestObserver incognito_observer(incognito_model);
+
+ // Right now, no actions are enabled in incognito mode.
+ EXPECT_EQ(0u, incognito_model->toolbar_items().size());
+
+ // Set extension B (which is overflowed) to be enabled in incognito. This
+ // results in b reloading, so wait for it.
+ {
+ extensions::TestExtensionRegistryObserver observer(registry(), extension_b);
+ extensions::util::SetIsIncognitoEnabled(extension_b, profile(), true);
+ observer.WaitForExtensionLoaded();
+ }
+
+ // Now, we should have one icon in the incognito bar. But, since B is
+ // overflowed in the main bar, it shouldn't be visible.
+ EXPECT_EQ(1u, incognito_model->toolbar_items().size());
+ EXPECT_EQ(extension_b, GetActionIdAtIndex(0u, incognito_model));
+ EXPECT_EQ(0u, incognito_model->visible_icon_count());
+
+ // Also enable extension a for incognito (again, wait for the reload).
+ {
+ extensions::TestExtensionRegistryObserver observer(registry(), extension_a);
+ extensions::util::SetIsIncognitoEnabled(extension_a, profile(), true);
+ observer.WaitForExtensionLoaded();
+ }
+
+ // Now, both extensions should be enabled in incognito mode. In addition, the
+ // incognito toolbar should have expanded to show extension A (since it isn't
+ // overflowed in the main bar).
+ EXPECT_EQ(2u, incognito_model->toolbar_items().size());
+ EXPECT_EQ(extension_a, GetActionIdAtIndex(0u, incognito_model));
+ EXPECT_EQ(extension_b, GetActionIdAtIndex(1u, incognito_model));
+ EXPECT_EQ(1u, incognito_model->visible_icon_count());
+}
+
+// Test that hiding actions on the toolbar results in sending them to the
+// overflow menu when the redesign switch is enabled.
+TEST_F(ToolbarActionsModelUnitTest,
+ ActionsToolbarActionsVisibilityWithSwitchAndComponentActions) {
+ extensions::FeatureSwitch::ScopedOverride enable_redesign(
+ extensions::FeatureSwitch::extension_action_redesign(), true);
+ Init();
+
+ // We choose to use all types of extensions here, since the misnamed
+ // BrowserActionVisibility is now for toolbar visibility.
+ ASSERT_TRUE(AddActionExtensions());
+
+ // For readability, alias extensions A B C.
+ const extensions::Extension* extension_a = browser_action();
+ const extensions::Extension* extension_b = page_action();
+ const extensions::Extension* extension_c = no_action();
+
+ // Sanity check: Order should start as A, B, C, with all three visible.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+ EXPECT_EQ(extension_a->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_b->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_c->id(), GetActionIdAtIndex(2u));
+
+ extensions::ExtensionActionAPI* action_api =
+ extensions::ExtensionActionAPI::Get(profile());
+
+ // By default, all actions should be visible.
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_a->id()));
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_c->id()));
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_b->id()));
+
+ // Hiding an action should result in it being sent to the overflow menu.
+ action_api->SetBrowserActionVisibility(extension_b->id(), false);
+
+ // Thus, the order should be A, C, B, with B in the overflow.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(extension_a->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_c->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_b->id(), GetActionIdAtIndex(2u));
+
+ // Hiding an extension's action should result in it being sent to the overflow
+ // as well, but as the _first_ extension in the overflow.
+ action_api->SetBrowserActionVisibility(extension_a->id(), false);
+ // Thus, the order should be C, A, B, with A and B in the overflow.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(extension_c->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_a->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_b->id(), GetActionIdAtIndex(2u));
+
+ // Resetting A's visibility to true should send it back to the visible icons
+ // (and should grow visible icons by 1), but it should be added to the end of
+ // the visible icon list (not to its original position).
+ action_api->SetBrowserActionVisibility(extension_a->id(), true);
+ // So order is C, A, B, with only B in the overflow.
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+ EXPECT_EQ(extension_c->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_a->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_b->id(), GetActionIdAtIndex(2u));
+
+ // Resetting B to be visible should make the order C, A, B, with no
+ // overflow.
+ action_api->SetBrowserActionVisibility(extension_b->id(), true);
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+ EXPECT_EQ(extension_c->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(extension_a->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(extension_b->id(), GetActionIdAtIndex(2u));
+
+ // Regression test for crbug.com/515963. Check that an extension's visibility
+ // is updated when it is moved out because another extension was removed.
+ toolbar_model()->SetVisibleIconCount(1);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(action_api->GetBrowserActionVisibility(extension_a->id()));
+ service()->DisableExtension(extension_c->id(),
+ extensions::Extension::DISABLE_USER_ACTION);
+ EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
+ EXPECT_TRUE(action_api->GetBrowserActionVisibility(extension_a->id()));
+}
+
+// Test that observers receive no Added notifications until after the
+// ExtensionSystem has initialized.
+TEST_F(ToolbarActionsModelUnitTest, ModelWaitsForExtensionSystemReady) {
+ InitializeEmptyExtensionService();
+ ToolbarActionsModel* toolbar_model = extensions::extension_action_test_util::
+ CreateToolbarModelForProfileWithoutWaitingForReady(profile());
+ ToolbarActionsModelTestObserver model_observer(toolbar_model);
+
+ EXPECT_TRUE(AddBrowserActionExtensions());
+
+ // Since the model hasn't been initialized (the ExtensionSystem::ready task
+ // hasn't been run), there should be no insertion notifications.
+ EXPECT_EQ(0u, model_observer.inserted_count());
+ EXPECT_EQ(0u, model_observer.initialized_count());
+ EXPECT_FALSE(toolbar_model->actions_initialized());
+
+ // Run the ready task.
+ static_cast<extensions::TestExtensionSystem*>(
+ extensions::ExtensionSystem::Get(profile()))
+ ->SetReady();
+ // Run tasks posted to TestExtensionSystem.
+ base::RunLoop().RunUntilIdle();
+
+ // We should still have no insertions, but should have an initialized count.
+ EXPECT_TRUE(toolbar_model->actions_initialized());
+ EXPECT_EQ(0u, model_observer.inserted_count());
+ EXPECT_EQ(1u, model_observer.initialized_count());
+}
+
+// Check that the toolbar model correctly clears and reorders when it detects
+// a preference change.
+TEST_F(ToolbarActionsModelUnitTest, ToolbarModelPrefChange) {
+ Init();
+
+ ASSERT_TRUE(AddBrowserActionExtensions());
+
+ // We should start in the basic A, B, C order.
+ ASSERT_TRUE(browser_action_a());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2));
+ // Record the difference between the inserted and removed counts. The actual
+ // value of the counts is not important, but we need to be sure that if we
+ // call to remove any, we also add them back.
+ size_t inserted_and_removed_difference =
+ observer()->inserted_count() - observer()->removed_count();
+
+ // Assign a new order, B, C, A, and write it in the prefs.
+ std::vector<std::string> new_order;
+ new_order.push_back(browser_action_b()->id());
+ new_order.push_back(browser_action_c()->id());
+ new_order.push_back(browser_action_a()->id());
+ extensions::ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order);
+
+ // Ensure everything has time to run.
+ base::RunLoop().RunUntilIdle();
+
+ // The new order should be reflected in the model.
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2));
+ EXPECT_EQ(inserted_and_removed_difference,
+ observer()->inserted_count() - observer()->removed_count());
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ComponentExtensionsAddedToEnd) {
+ Init();
+
+ ASSERT_TRUE(AddBrowserActionExtensions());
+
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2));
+
+ const char kName[] = "component";
+ extensions::DictionaryBuilder manifest;
+ manifest.Set("name", kName)
+ .Set("description", "An extension")
+ .Set("manifest_version", 2)
+ .Set("version", "1.0.0")
+ .Set("browser_action", extensions::DictionaryBuilder().Pass());
+ scoped_refptr<const extensions::Extension> component_extension =
+ extensions::ExtensionBuilder()
+ .SetManifest(manifest.Pass())
+ .SetID(crx_file::id_util::GenerateId(kName))
+ .SetLocation(extensions::Manifest::COMPONENT)
+ .Build();
+ service()->AddExtension(component_extension.get());
+
+ EXPECT_EQ(component_extension.get()->id(), GetActionIdAtIndex(0));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(3));
+}
+
+TEST_F(ToolbarActionsModelUnitTest, ToolbarModelHighlightsForToolbarRedesign) {
+ extensions::FeatureSwitch::ScopedOverride enable_redesign(
+ extensions::FeatureSwitch::extension_action_redesign(), true);
+ InitializeEmptyExtensionService();
+ EXPECT_TRUE(AddActionExtensions());
+ ToolbarActionsModel* toolbar_model =
+ extensions::extension_action_test_util::CreateToolbarModelForProfile(
+ profile());
+ EXPECT_TRUE(toolbar_model);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
+ profile()));
+ EXPECT_TRUE(toolbar_model->is_highlighting());
+ EXPECT_EQ(ToolbarActionsModel::HIGHLIGHT_INFO,
+ toolbar_model->highlight_type());
+ EXPECT_EQ(3u, toolbar_model->visible_icon_count());
+ EXPECT_EQ(3u, toolbar_model->toolbar_items().size());
+
+ scoped_ptr<ToolbarActionsBarBubbleDelegate> bubble(
+ new ExtensionToolbarIconSurfacingBubbleDelegate(profile()));
+ bubble->OnBubbleClosed(ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS);
+
+ EXPECT_FALSE(toolbar_model->is_highlighting());
+ EXPECT_EQ(ToolbarActionsModel::HIGHLIGHT_NONE,
+ toolbar_model->highlight_type());
+}
+
+// Test various different reorderings, removals, and reinsertions of the
+// toolbar with component actions.
+TEST_F(ToolbarActionsModelUnitTest,
+ ActionsToolbarReorderAndReinsertWithSwitchAndCOmponentActions) {
+ extensions::FeatureSwitch::ScopedOverride enable_redesign(
+ extensions::FeatureSwitch::extension_action_redesign(), true);
+ SetMockActionsFactory(new MockComponentToolbarActionsFactory(nullptr));
+ Init();
+
+ // One component action was added when the model was initialized.
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
+
+ // Add the three browser action extensions.
+ ASSERT_TRUE(AddBrowserActionExtensions());
+
+ // Verify the four actions are in the model in the proper order.
+ EXPECT_EQ(4u, num_toolbar_items());
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(3u));
+
+ // Order is now MCA, A, B, C. Let's put C first.
+ toolbar_model()->MoveActionIcon(browser_action_c()->id(), 0);
+ EXPECT_EQ(1u, observer()->moved_count());
+ EXPECT_EQ(4u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(3u));
+
+ // Order is now C, MCA, A, B. Let's put MCA last.
+ toolbar_model()->MoveActionIcon(component_action_id(), 3);
+ EXPECT_EQ(2u, observer()->moved_count());
+ EXPECT_EQ(4u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(3u));
+
+ // Order is now C, A, B, MCA. Move MCA to the location it already occupies.
+ toolbar_model()->MoveActionIcon(component_action_id(), 3);
+ EXPECT_EQ(3u, observer()->moved_count());
+ EXPECT_EQ(4u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(3u));
+
+ // Order is still C, A, B, MCA. Move MCA to second to last, in preparation
+ // for visibility checks.
+ toolbar_model()->MoveActionIcon(component_action_id(), 2);
+ EXPECT_EQ(4u, observer()->moved_count());
+ EXPECT_EQ(4u, num_toolbar_items());
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(2u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(3u));
+
+ // Order is now C, A, MCA, B. Show only three icons: C, A, MCA, [B].
+ toolbar_model()->SetVisibleIconCount(3);
+ EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
+ EXPECT_FALSE(toolbar_model()->all_icons_visible());
+
+ // Show only two icons so we test MCA in the overflow. The icons should
+ // be: C, A, [MCA], [B].
+ toolbar_model()->SetVisibleIconCount(2);
+ EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
+ EXPECT_FALSE(toolbar_model()->all_icons_visible());
+
+ // Show all the icons again. Order should be C, A, MCA, B.
+ toolbar_model()->SetVisibleIconCount(4);
+ EXPECT_EQ(4u, toolbar_model()->visible_icon_count());
+ EXPECT_TRUE(toolbar_model()->all_icons_visible());
+
+ // Order is C, A, MCA, B. Remove C.
+ ASSERT_TRUE(RemoveExtension(browser_action_c()));
+ EXPECT_EQ(1u, observer()->removed_count());
+ EXPECT_EQ(3u, num_toolbar_items());
+ EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
+
+ // Order is now A, MCA, B. Remove A.
+ ASSERT_TRUE(RemoveExtension(browser_action_a()));
+ EXPECT_EQ(2u, observer()->removed_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
+
+ // Order is now MCA, B. Remove B.
+ ASSERT_TRUE(RemoveExtension(browser_action_b()));
+ EXPECT_EQ(3u, observer()->removed_count());
+ EXPECT_EQ(1u, num_toolbar_items());
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
+
+ // Load extension C again.
+ ASSERT_TRUE(AddExtension(browser_action_c()));
+ EXPECT_EQ(4u, observer()->inserted_count());
+ EXPECT_EQ(2u, num_toolbar_items());
+ // Make sure it gets its old spot in the list (at the beginning).
+ EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
+ EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));
+}
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.cc b/chrome/browser/ui/toolbar/wrench_menu_model.cc
index a55fb98..5f9ca12 100644
--- a/chrome/browser/ui/toolbar/wrench_menu_model.cc
+++ b/chrome/browser/ui/toolbar/wrench_menu_model.cc
@@ -16,7 +16,6 @@
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/profiles/profile.h"
@@ -35,9 +34,9 @@
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
-#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
#include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -89,7 +88,7 @@ namespace {
#if defined(OS_MACOSX)
// An empty command used because of a bug in AppKit menus.
-// See comment in CreateExtensionToolbarOverflowMenu().
+// See comment in CreateActionToolbarOverflowMenu().
const int kEmptyMenuItemCommand = 0;
#endif
@@ -786,7 +785,7 @@ bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
switch (command_id) {
#if defined(OS_MACOSX)
case kEmptyMenuItemCommand:
- return false; // Always hidden (see CreateExtensionToolbarOverflowMenu).
+ return false; // Always hidden (see CreateActionToolbarOverflowMenu).
#endif
#if defined(OS_WIN)
case IDC_VIEW_INCOMPATIBILITIES: {
@@ -883,7 +882,7 @@ bool WrenchMenuModel::ShouldShowNewIncognitoWindowMenuItem() {
// - Browser relaunch, quit.
void WrenchMenuModel::Build() {
if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
- CreateExtensionToolbarOverflowMenu();
+ CreateActionToolbarOverflowMenu();
AddItem(IDC_VIEW_INCOMPATIBILITIES,
l10n_util::GetStringUTF16(IDS_VIEW_INCOMPATIBILITIES));
@@ -1030,15 +1029,10 @@ bool WrenchMenuModel::AddGlobalErrorMenuItems() {
return menu_items_added;
}
-void WrenchMenuModel::CreateExtensionToolbarOverflowMenu() {
+void WrenchMenuModel::CreateActionToolbarOverflowMenu() {
// We only add the extensions overflow container if there are any icons that
- // aren't shown in the main container or if there are component actions.
- // TODO(apacible): Remove check for component actions when
- // ExtensionToolbarModel can support them.
- if (!extensions::ExtensionToolbarModel::Get(browser_->profile())->
- all_icons_visible() ||
- ComponentToolbarActionsFactory::GetInstance()->
- GetNumComponentActions(browser_) > 0) {
+ // aren't shown in the main container.
+ if (!ToolbarActionsModel::Get(browser_->profile())->all_icons_visible()) {
#if defined(OS_MACOSX)
// There's a bug in AppKit menus, where if a menu item with a custom view
// (like the extensions overflow menu) is the first menu item, it is not
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.h b/chrome/browser/ui/toolbar/wrench_menu_model.h
index b6751ef..525f47d 100644
--- a/chrome/browser/ui/toolbar/wrench_menu_model.h
+++ b/chrome/browser/ui/toolbar/wrench_menu_model.h
@@ -193,8 +193,8 @@ class WrenchMenuModel : public ui::SimpleMenuModel,
// clipboard menu content and the finalizing menu break.
void CreateCutCopyPasteMenu();
- // Add a menu item for the extension icons.
- void CreateExtensionToolbarOverflowMenu();
+ // Add a menu item for the browser action icons.
+ void CreateActionToolbarOverflowMenu();
// Appends everything needed for the zoom menu: a menu break, then the zoom
// menu content and then another menu break.
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
index b94289a..07a9625 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -7,7 +7,6 @@
#include "base/compiler_specific.h"
#include "base/stl_util.h"
#include "chrome/browser/extensions/extension_message_bubble_controller.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
@@ -15,6 +14,7 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/browser/ui/toolbar/wrench_menu_badge_controller.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
@@ -702,10 +702,10 @@ void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) {
// paint (one will be triggered by entering highlight mode).
if (toolbar_actions_bar_->is_highlighting() &&
!toolbar_action_views_.empty() && !in_overflow_mode()) {
- extensions::ExtensionToolbarModel::HighlightType highlight_type =
+ ToolbarActionsModel::HighlightType highlight_type =
toolbar_actions_bar_->highlight_type();
views::Painter* painter =
- highlight_type == extensions::ExtensionToolbarModel::HIGHLIGHT_INFO
+ highlight_type == ToolbarActionsModel::HIGHLIGHT_INFO
? info_highlight_painter_.get()
: warning_highlight_painter_.get();
views::Painter::PaintPainterAt(canvas, painter, GetLocalBounds());
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
index 05d3dbc..9988a54 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
@@ -6,14 +6,15 @@
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
@@ -61,10 +62,15 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, DragBrowserActions) {
EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(1));
EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
+ const extensions::ExtensionSet& extension_set =
+ extensions::ExtensionRegistry::Get(profile())->enabled_extensions();
+ const std::vector<ToolbarActionsModel::ToolbarItem>& toolbar_items =
+ toolbar_model()->toolbar_items();
+
// This order should be reflected in the underlying model.
- EXPECT_EQ(extension_b(), toolbar_model()->toolbar_items()[0].get());
- EXPECT_EQ(extension_a(), toolbar_model()->toolbar_items()[1].get());
- EXPECT_EQ(extension_c(), toolbar_model()->toolbar_items()[2].get());
+ EXPECT_EQ(extension_b(), extension_set.GetByID(toolbar_items[0].id));
+ EXPECT_EQ(extension_a(), extension_set.GetByID(toolbar_items[1].id));
+ EXPECT_EQ(extension_c(), extension_set.GetByID(toolbar_items[2].id));
// Simulate a drag and drop to the left.
ui::OSExchangeData drop_data2;
@@ -181,7 +187,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, MultipleWindows) {
// Test that the BrowserActionsContainer responds correctly when the underlying
// model enters highlight mode, and that browser actions are undraggable in
// highlight mode. (Highlight mode itself it tested more thoroughly in the
-// ExtensionToolbarModel browsertests).
+// ToolbarActionsModel browsertests).
IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, HighlightMode) {
LoadExtensions();
@@ -198,11 +204,11 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, HighlightMode) {
gfx::Point point(action_view->x(), action_view->y());
EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
- extensions::ExtensionIdList extension_ids;
- extension_ids.push_back(extension_a()->id());
- extension_ids.push_back(extension_b()->id());
- toolbar_model()->HighlightExtensions(
- extension_ids, extensions::ExtensionToolbarModel::HIGHLIGHT_WARNING);
+ std::vector<std::string> action_ids;
+ action_ids.push_back(extension_a()->id());
+ action_ids.push_back(extension_b()->id());
+ toolbar_model()->HighlightActions(action_ids,
+ ToolbarActionsModel::HIGHLIGHT_WARNING);
// Only two browser actions should be visible.
EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
@@ -342,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
// Move extension C to the first position. Order should now be C A B, with
// C and A visible in the main bar.
- toolbar_model()->MoveExtensionIcon(extension_c()->id(), 0);
+ toolbar_model()->MoveActionIcon(extension_c()->id(), 0);
overflow_bar()->Layout(); // Kick.
EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(0u));
EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
diff --git a/chrome/browser/ui/views/toolbar/chevron_menu_button.cc b/chrome/browser/ui/views/toolbar/chevron_menu_button.cc
index 57ca038..25b5f70 100644
--- a/chrome/browser/ui/views/toolbar/chevron_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/chevron_menu_button.cc
@@ -12,7 +12,6 @@
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_icon_factory.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/extension_action_view_controller.h"
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 3558125..7996c5e 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -709,10 +709,6 @@
'browser/extensions/extension_system_impl.h',
'browser/extensions/extension_tab_util.cc',
'browser/extensions/extension_tab_util.h',
- 'browser/extensions/extension_toolbar_model.cc',
- 'browser/extensions/extension_toolbar_model.h',
- 'browser/extensions/extension_toolbar_model_factory.cc',
- 'browser/extensions/extension_toolbar_model_factory.h',
'browser/extensions/extension_ui_util.cc',
'browser/extensions/extension_ui_util.h',
'browser/extensions/extension_uninstall_dialog.cc',
@@ -870,6 +866,10 @@
'browser/extensions/window_controller_list_observer.h',
'browser/extensions/zipfile_installer.cc',
'browser/extensions/zipfile_installer.h',
+ 'browser/ui/toolbar/toolbar_actions_model.cc',
+ 'browser/ui/toolbar/toolbar_actions_model.h',
+ 'browser/ui/toolbar/toolbar_actions_model_factory.cc',
+ 'browser/ui/toolbar/toolbar_actions_model_factory.h',
'browser/web_applications/update_shortcut_worker_win.cc',
'browser/web_applications/update_shortcut_worker_win.h',
'browser/web_applications/web_app.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index ade51cc..51d8b7e 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -522,6 +522,8 @@
'browser/ui/toolbar/browser_actions_bar_browsertest.cc',
'browser/ui/toolbar/browser_actions_bar_browsertest.h',
'browser/ui/toolbar/component_toolbar_actions_browsertest.cc',
+ 'browser/ui/toolbar/mock_component_toolbar_actions_factory.cc',
+ 'browser/ui/toolbar/mock_component_toolbar_actions_factory.h',
'browser/ui/toolbar/test_toolbar_model.cc',
'browser/ui/toolbar/test_toolbar_model.h',
'browser/ui/website_settings/mock_permission_bubble_view.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index b93eee2..09d4b36 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -736,7 +736,6 @@
'browser/extensions/extension_special_storage_policy_unittest.cc',
'browser/extensions/extension_sync_data_unittest.cc',
'browser/extensions/extension_test_message_listener_unittest.cc',
- 'browser/extensions/extension_toolbar_model_unittest.cc',
'browser/extensions/extension_user_script_loader_unittest.cc',
'browser/extensions/extension_web_ui_unittest.cc',
'browser/extensions/external_policy_loader_unittest.cc',
@@ -1561,6 +1560,8 @@
'browser/ui/toolbar/back_forward_menu_model_unittest.cc',
'browser/ui/toolbar/encoding_menu_controller_unittest.cc',
'browser/ui/toolbar/media_router_action_unittest.cc',
+ 'browser/ui/toolbar/mock_component_toolbar_actions_factory.cc',
+ 'browser/ui/toolbar/mock_component_toolbar_actions_factory.h',
'browser/ui/toolbar/recent_tabs_builder_test_helper.cc',
'browser/ui/toolbar/recent_tabs_builder_test_helper.h',
'browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc',
@@ -1568,6 +1569,7 @@
'browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h',
'browser/ui/toolbar/test_toolbar_model.cc',
'browser/ui/toolbar/test_toolbar_model.h',
+ 'browser/ui/toolbar/toolbar_actions_model_unittest.cc',
'browser/ui/toolbar/toolbar_actions_bar_unittest.cc',
'browser/ui/toolbar/toolbar_actions_bar_unittest.h',
'browser/ui/toolbar/toolbar_model_unittest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index a18553e..5b0c603 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -446,10 +446,8 @@ const char kEnableMaterialDesignDownloads[] = "enable-md-downloads";
// Enables the material design Settings feature.
const char kEnableMaterialDesignSettings[] = "enable-md-settings";
-#if defined(ENABLE_MEDIA_ROUTER)
// Enables Media Router.
const char kEnableMediaRouter[] = "enable-media-router";
-#endif
// Runs the Native Client inside the renderer process and enables GPU plugin
// (internally adds lEnableGpuPlugin to the command line).
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 77cb470..9b3bc08 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -46793,6 +46793,38 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
<summary>Number of retries until the final response was recorded.</summary>
</histogram>
+<histogram name="Toolbar.ActionsModel.ComponentActionsCount">
+ <owner>rdevlin.cronin@chromium.org</owner>
+ <summary>
+ The number of component action icons the Browser Actions Container knows
+ about (visible or in the overflow bucket). Does not count icons that have
+ been permanently hidden by the user. Measured once per startup per
+ (non-incognito) profile.
+ </summary>
+</histogram>
+
+<histogram name="Toolbar.ActionsModel.OverallActionsCount">
+ <owner>rdevlin.cronin@chromium.org</owner>
+ <summary>
+ The total number of action icons the Browser Actions Container knows about
+ (visible or in the overflow bucket). Does not count icons that have been
+ permanently hidden by the user. Measured once per startup per
+ (non-incognito) profile.
+ </summary>
+</histogram>
+
+<histogram name="Toolbar.ActionsModel.ToolbarActionsVisible">
+ <owner>rdevlin.cronin@chromium.org</owner>
+ <summary>
+ The number of visible toolbar icons in the Browser Actions Container
+ (visible as in number of icons not in the overflow bucket). 0 means all
+ icons are in the overflow bucket. MAX_INT means the toolbar is always
+ showing all icons. Measured once per startup per (non-incognito) profile but
+ only for those profiles that have one or more browser actions showing in the
+ toolbar.
+ </summary>
+</histogram>
+
<histogram name="TopSites.NumberOfApplyBlacklist">
<owner>Please list the metric's owners. Add more owner tags as needed.</owner>
<summary>The number of times TopSitesImpl::ApplyBlacklist is called.</summary>