Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / extension_action / extension_action_api.cc
index 470af85..fb05935 100644 (file)
@@ -4,50 +4,41 @@
 
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 
-#include "base/base64.h"
 #include "base/lazy_instance.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
 #include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h"
-#include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_action.h"
+#include "chrome/browser/extensions/active_script_controller.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_function_registry.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/extensions/location_bar_controller.h"
-#include "chrome/browser/extensions/state_store.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/sessions/session_tab_helper.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/render_messages.h"
-#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_function_registry.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/image_util.h"
+#include "extensions/browser/notification_types.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/feature_switch.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 
 using content::WebContents;
 
-namespace page_actions_keys = extension_page_actions_api_constants;
-
 namespace extensions {
 
 namespace {
 
-const char kBrowserActionStorageKey[] = "browser_action";
-const char kPopupUrlStorageKey[] = "poupup_url";
-const char kTitleStorageKey[] = "title";
-const char kIconStorageKey[] = "icon";
-const char kBadgeTextStorageKey[] = "badge_text";
-const char kBadgeBackgroundColorStorageKey[] = "badge_background_color";
-const char kBadgeTextColorStorageKey[] = "badge_text_color";
-const char kAppearanceStorageKey[] = "appearance";
-
 // Whether the browser action is visible in the toolbar.
 const char kBrowserActionVisible[] = "browser_action_visible";
 
@@ -55,148 +46,41 @@ const char kBrowserActionVisible[] = "browser_action_visible";
 const char kNoExtensionActionError[] =
     "This extension has no action specified.";
 const char kNoTabError[] = "No tab with id: *.";
-const char kNoPageActionError[] =
-    "This extension has no page action specified.";
-const char kUrlNotActiveError[] = "This url is no longer active: *.";
 const char kOpenPopupError[] =
     "Failed to show popup either because there is an existing popup or another "
     "error occurred.";
-const char kInternalError[] = "Internal error.";
-
-struct IconRepresentationInfo {
-  // Size as a string that will be used to retrieve representation value from
-  // SetIcon function arguments.
-  const char* size_string;
-  // Scale factor for which the represantion should be used.
-  ui::ScaleFactor scale;
-};
-
-const IconRepresentationInfo kIconSizes[] = {
-    { "19", ui::SCALE_FACTOR_100P },
-    { "38", ui::SCALE_FACTOR_200P }
-};
-
-// Conversion function for reading/writing to storage.
-SkColor RawStringToSkColor(const std::string& str) {
-  uint64 value = 0;
-  base::StringToUint64(str, &value);
-  SkColor color = static_cast<SkColor>(value);
-  DCHECK(value == color);  // ensure value fits into color's 32 bits
-  return color;
-}
-
-// Conversion function for reading/writing to storage.
-std::string SkColorToRawString(SkColor color) {
-  return base::Uint64ToString(color);
-}
-
-// Conversion function for reading/writing to storage.
-bool StringToSkBitmap(const std::string& str, SkBitmap* bitmap) {
-  // TODO(mpcomplete): Remove the base64 encode/decode step when
-  // http://crbug.com/140546 is fixed.
-  std::string raw_str;
-  if (!base::Base64Decode(str, &raw_str))
-    return false;
-  IPC::Message bitmap_pickle(raw_str.data(), raw_str.size());
-  PickleIterator iter(bitmap_pickle);
-  return IPC::ReadParam(&bitmap_pickle, &iter, bitmap);
-}
-
-// Conversion function for reading/writing to storage.
-std::string RepresentationToString(const gfx::ImageSkia& image, float scale) {
-  SkBitmap bitmap = image.GetRepresentation(scale).sk_bitmap();
-  IPC::Message bitmap_pickle;
-  // Clear the header values so they don't vary in serialization.
-  bitmap_pickle.SetHeaderValues(0, 0, 0);
-  IPC::WriteParam(&bitmap_pickle, bitmap);
-  std::string raw_str(static_cast<const char*>(bitmap_pickle.data()),
-                      bitmap_pickle.size());
-  std::string base64_str;
-  if (!base::Base64Encode(raw_str, &base64_str))
-    return std::string();
-  return base64_str;
-}
-
-// Set |action|'s default values to those specified in |dict|.
-void SetDefaultsFromValue(const base::DictionaryValue* dict,
-                          ExtensionAction* action) {
-  const int kTabId = ExtensionAction::kDefaultTabId;
-  std::string str_value;
-  int int_value;
-  SkBitmap bitmap;
-  gfx::ImageSkia icon;
-
-  if (dict->GetString(kPopupUrlStorageKey, &str_value))
-    action->SetPopupUrl(kTabId, GURL(str_value));
-  if (dict->GetString(kTitleStorageKey, &str_value))
-    action->SetTitle(kTabId, str_value);
-  if (dict->GetString(kBadgeTextStorageKey, &str_value))
-    action->SetBadgeText(kTabId, str_value);
-  if (dict->GetString(kBadgeBackgroundColorStorageKey, &str_value))
-    action->SetBadgeBackgroundColor(kTabId, RawStringToSkColor(str_value));
-  if (dict->GetString(kBadgeTextColorStorageKey, &str_value))
-    action->SetBadgeTextColor(kTabId, RawStringToSkColor(str_value));
-  if (dict->GetInteger(kAppearanceStorageKey, &int_value))
-    action->SetAppearance(kTabId,
-                          static_cast<ExtensionAction::Appearance>(int_value));
-
-  const base::DictionaryValue* icon_value = NULL;
-  if (dict->GetDictionary(kIconStorageKey, &icon_value)) {
-    for (size_t i = 0; i < arraysize(kIconSizes); i++) {
-      if (icon_value->GetString(kIconSizes[i].size_string, &str_value) &&
-          StringToSkBitmap(str_value, &bitmap)) {
-        CHECK(!bitmap.isNull());
-        float scale = ui::GetImageScale(kIconSizes[i].scale);
-        icon.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
-      }
-    }
-    action->SetIcon(kTabId, gfx::Image(icon));
-  }
+
+}  // namespace
+
+//
+// ExtensionActionAPI::Observer
+//
+
+void ExtensionActionAPI::Observer::OnExtensionActionUpdated(
+    ExtensionAction* extension_action,
+    content::WebContents* web_contents,
+    content::BrowserContext* browser_context) {
 }
 
-// Store |action|'s default values in a DictionaryValue for use in storing to
-// disk.
-scoped_ptr<base::DictionaryValue> DefaultsToValue(ExtensionAction* action) {
-  const int kTabId = ExtensionAction::kDefaultTabId;
-  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString(kPopupUrlStorageKey, action->GetPopupUrl(kTabId).spec());
-  dict->SetString(kTitleStorageKey, action->GetTitle(kTabId));
-  dict->SetString(kBadgeTextStorageKey, action->GetBadgeText(kTabId));
-  dict->SetString(kBadgeBackgroundColorStorageKey,
-                  SkColorToRawString(action->GetBadgeBackgroundColor(kTabId)));
-  dict->SetString(kBadgeTextColorStorageKey,
-                  SkColorToRawString(action->GetBadgeTextColor(kTabId)));
-  dict->SetInteger(kAppearanceStorageKey,
-                   action->GetIsVisible(kTabId) ?
-                       ExtensionAction::ACTIVE : ExtensionAction::INVISIBLE);
-
-  gfx::ImageSkia icon = action->GetExplicitlySetIcon(kTabId);
-  if (!icon.isNull()) {
-    base::DictionaryValue* icon_value = new base::DictionaryValue();
-    for (size_t i = 0; i < arraysize(kIconSizes); i++) {
-      float scale = ui::GetImageScale(kIconSizes[i].scale);
-      if (icon.HasRepresentation(scale)) {
-        icon_value->SetString(
-            kIconSizes[i].size_string,
-            RepresentationToString(icon, scale));
-      }
-    }
-    dict->Set(kIconStorageKey, icon_value);
-  }
-  return dict.Pass();
+void ExtensionActionAPI::Observer::OnPageActionsUpdated(
+    content::WebContents* web_contents) {
 }
 
-}  // namespace
+void ExtensionActionAPI::Observer::OnExtensionActionAPIShuttingDown() {
+}
+
+ExtensionActionAPI::Observer::~Observer() {
+}
 
 //
 // ExtensionActionAPI
 //
 
-static base::LazyInstance<ProfileKeyedAPIFactory<ExtensionActionAPI> >
+static base::LazyInstance<BrowserContextKeyedAPIFactory<ExtensionActionAPI> >
     g_factory = LAZY_INSTANCE_INITIALIZER;
 
-ExtensionActionAPI::ExtensionActionAPI(Profile* profile) {
+ExtensionActionAPI::ExtensionActionAPI(content::BrowserContext* context)
+    : browser_context_(context) {
   ExtensionFunctionRegistry* registry =
       ExtensionFunctionRegistry::GetInstance();
 
@@ -215,8 +99,6 @@ ExtensionActionAPI::ExtensionActionAPI(Profile* profile) {
   registry->RegisterFunction<BrowserActionOpenPopupFunction>();
 
   // Page Actions
-  registry->RegisterFunction<EnablePageActionsFunction>();
-  registry->RegisterFunction<DisablePageActionsFunction>();
   registry->RegisterFunction<PageActionShowFunction>();
   registry->RegisterFunction<PageActionHideFunction>();
   registry->RegisterFunction<PageActionSetIconFunction>();
@@ -224,25 +106,20 @@ ExtensionActionAPI::ExtensionActionAPI(Profile* profile) {
   registry->RegisterFunction<PageActionSetPopupFunction>();
   registry->RegisterFunction<PageActionGetTitleFunction>();
   registry->RegisterFunction<PageActionGetPopupFunction>();
-
-  // Script Badges
-  registry->RegisterFunction<ScriptBadgeGetAttentionFunction>();
-  registry->RegisterFunction<ScriptBadgeGetPopupFunction>();
-  registry->RegisterFunction<ScriptBadgeSetPopupFunction>();
 }
 
 ExtensionActionAPI::~ExtensionActionAPI() {
 }
 
 // static
-ProfileKeyedAPIFactory<ExtensionActionAPI>*
+BrowserContextKeyedAPIFactory<ExtensionActionAPI>*
 ExtensionActionAPI::GetFactoryInstance() {
-  return &g_factory.Get();
+  return g_factory.Pointer();
 }
 
 // static
-ExtensionActionAPI* ExtensionActionAPI::Get(Profile* profile) {
-  return ProfileKeyedAPIFactory<ExtensionActionAPI>::GetForProfile(profile);
+ExtensionActionAPI* ExtensionActionAPI::Get(content::BrowserContext* context) {
+  return BrowserContextKeyedAPIFactory<ExtensionActionAPI>::Get(context);
 }
 
 // static
@@ -270,88 +147,158 @@ void ExtensionActionAPI::SetBrowserActionVisibility(
                              kBrowserActionVisible,
                              new base::FundamentalValue(visible));
   content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
+      NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
       content::Source<ExtensionPrefs>(prefs),
       content::Details<const std::string>(&extension_id));
 }
 
-// static
-void ExtensionActionAPI::BrowserActionExecuted(
-    Profile* profile,
-    const ExtensionAction& browser_action,
-    WebContents* web_contents) {
-  ExtensionActionExecuted(profile, browser_action, web_contents);
+void ExtensionActionAPI::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
 }
 
-// static
-void ExtensionActionAPI::PageActionExecuted(Profile* profile,
-                                            const ExtensionAction& page_action,
-                                            int tab_id,
-                                            const std::string& url,
-                                            int button) {
-  DispatchOldPageActionEvent(profile, page_action.extension_id(),
-                             page_action.id(), tab_id, url, button);
-  WebContents* web_contents = NULL;
-  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
-                                    NULL, NULL, &web_contents, NULL)) {
-    return;
+void ExtensionActionAPI::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+ExtensionAction::ShowAction ExtensionActionAPI::ExecuteExtensionAction(
+    const Extension* extension,
+    Browser* browser,
+    bool grant_active_tab_permissions) {
+  content::WebContents* web_contents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  if (!web_contents)
+    return ExtensionAction::ACTION_NONE;
+
+  int tab_id = SessionTabHelper::IdForTab(web_contents);
+
+  ActiveScriptController* active_script_controller =
+      ActiveScriptController::GetForWebContents(web_contents);
+  bool has_pending_scripts = false;
+  if (active_script_controller &&
+      active_script_controller->WantsToRun(extension)) {
+    has_pending_scripts = true;
   }
-  ExtensionActionExecuted(profile, page_action, web_contents);
+
+  // Grant active tab if appropriate.
+  if (grant_active_tab_permissions) {
+    TabHelper::FromWebContents(web_contents)->active_tab_permission_granter()->
+        GrantIfRequested(extension);
+  }
+
+  // If this was a request to run a script, it will have been run once active
+  // tab was granted. Return without executing the action, since we should only
+  // run pending scripts OR the extension action, not both.
+  if (has_pending_scripts)
+    return ExtensionAction::ACTION_NONE;
+
+  ExtensionAction* extension_action =
+      ExtensionActionManager::Get(browser_context_)->GetExtensionAction(
+          *extension);
+
+  // Anything that gets here should have a page or browser action.
+  DCHECK(extension_action);
+  if (!extension_action->GetIsVisible(tab_id))
+    return ExtensionAction::ACTION_NONE;
+
+  if (extension_action->HasPopup(tab_id))
+    return ExtensionAction::ACTION_SHOW_POPUP;
+
+  ExtensionActionExecuted(*extension_action, web_contents);
+  return ExtensionAction::ACTION_NONE;
 }
 
-// static
-void ExtensionActionAPI::ScriptBadgeExecuted(
-    Profile* profile,
-    const ExtensionAction& script_badge,
-    int tab_id) {
-  WebContents* web_contents = NULL;
-  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
-                                    NULL, NULL, &web_contents, NULL)) {
-    return;
+bool ExtensionActionAPI::ShowExtensionActionPopup(
+    const Extension* extension,
+    Browser* browser,
+    bool grant_active_tab_permissions) {
+  ExtensionAction* extension_action =
+      ExtensionActionManager::Get(browser_context_)->GetExtensionAction(
+          *extension);
+  if (!extension_action)
+    return false;
+
+  if (extension_action->action_type() == ActionInfo::TYPE_PAGE &&
+      !FeatureSwitch::extension_action_redesign()->IsEnabled()) {
+    // We show page actions in the location bar unless the new toolbar is
+    // enabled.
+    return browser->window()->GetLocationBar()->ShowPageActionPopup(
+        extension, grant_active_tab_permissions);
+  } else {
+    return ExtensionToolbarModel::Get(browser->profile())->
+        ShowExtensionActionPopup(
+            extension, browser, grant_active_tab_permissions);
+  }
+}
+
+bool ExtensionActionAPI::ExtensionWantsToRun(
+    const Extension* extension, content::WebContents* web_contents) {
+  // An extension wants to act if it has a visible page action on the given
+  // page...
+  ExtensionAction* page_action =
+      ExtensionActionManager::Get(browser_context_)->GetPageAction(*extension);
+  if (page_action &&
+      page_action->GetIsVisible(SessionTabHelper::IdForTab(web_contents)))
+    return true;
+
+  // ... Or if it has pending scripts that need approval for execution.
+  ActiveScriptController* active_script_controller =
+      ActiveScriptController::GetForWebContents(web_contents);
+  if (active_script_controller &&
+      active_script_controller->WantsToRun(extension))
+    return true;
+
+  return false;
+}
+
+void ExtensionActionAPI::NotifyChange(ExtensionAction* extension_action,
+                                      content::WebContents* web_contents,
+                                      content::BrowserContext* context) {
+  FOR_EACH_OBSERVER(
+      Observer,
+      observers_,
+      OnExtensionActionUpdated(extension_action, web_contents, context));
+
+  if (extension_action->action_type() == ActionInfo::TYPE_PAGE)
+    NotifyPageActionsChanged(web_contents);
+}
+
+void ExtensionActionAPI::ClearAllValuesForTab(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  int tab_id = SessionTabHelper::IdForTab(web_contents);
+  content::BrowserContext* browser_context = web_contents->GetBrowserContext();
+  const ExtensionSet& enabled_extensions =
+      ExtensionRegistry::Get(browser_context_)->enabled_extensions();
+  ExtensionActionManager* action_manager =
+      ExtensionActionManager::Get(browser_context_);
+
+  for (ExtensionSet::const_iterator iter = enabled_extensions.begin();
+       iter != enabled_extensions.end(); ++iter) {
+    ExtensionAction* extension_action =
+        action_manager->GetExtensionAction(**iter);
+    if (extension_action) {
+      extension_action->ClearAllValuesForTab(tab_id);
+      NotifyChange(extension_action, web_contents, browser_context);
+    }
   }
-  ExtensionActionExecuted(profile, script_badge, web_contents);
 }
 
-// static
 void ExtensionActionAPI::DispatchEventToExtension(
-    Profile* profile,
+    content::BrowserContext* context,
     const std::string& extension_id,
     const std::string& event_name,
     scoped_ptr<base::ListValue> event_args) {
-  if (!extensions::ExtensionSystem::Get(profile)->event_router())
+  if (!EventRouter::Get(context))
     return;
 
   scoped_ptr<Event> event(new Event(event_name, event_args.Pass()));
-  event->restrict_to_profile = profile;
+  event->restrict_to_browser_context = context;
   event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
-  ExtensionSystem::Get(profile)->event_router()->
-      DispatchEventToExtension(extension_id, event.Pass());
-}
-
-// static
-void ExtensionActionAPI::DispatchOldPageActionEvent(
-    Profile* profile,
-    const std::string& extension_id,
-    const std::string& page_action_id,
-    int tab_id,
-    const std::string& url,
-    int button) {
-  scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(new base::StringValue(page_action_id));
-
-  DictionaryValue* data = new DictionaryValue();
-  data->Set(page_actions_keys::kTabIdKey, new base::FundamentalValue(tab_id));
-  data->Set(page_actions_keys::kTabUrlKey, new base::StringValue(url));
-  data->Set(page_actions_keys::kButtonKey,
-            new base::FundamentalValue(button));
-  args->Append(data);
-
-  DispatchEventToExtension(profile, extension_id, "pageActions", args.Pass());
+  EventRouter::Get(context)
+      ->DispatchEventToExtension(extension_id, event.Pass());
 }
 
-// static
 void ExtensionActionAPI::ExtensionActionExecuted(
-    Profile* profile,
     const ExtensionAction& extension_action,
     WebContents* web_contents) {
   const char* event_name = NULL;
@@ -362,9 +309,6 @@ void ExtensionActionAPI::ExtensionActionExecuted(
     case ActionInfo::TYPE_PAGE:
       event_name = "pageAction.onClicked";
       break;
-    case ActionInfo::TYPE_SCRIPT_BADGE:
-      event_name = "scriptBadge.onClicked";
-      break;
     case ActionInfo::TYPE_SYSTEM_INDICATOR:
       // The System Indicator handles its own clicks.
       break;
@@ -372,111 +316,34 @@ void ExtensionActionAPI::ExtensionActionExecuted(
 
   if (event_name) {
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(
-        web_contents);
+    base::DictionaryValue* tab_value =
+        ExtensionTabUtil::CreateTabValue(web_contents);
     args->Append(tab_value);
 
-    DispatchEventToExtension(profile,
-                             extension_action.extension_id(),
-                             event_name,
-                             args.Pass());
-  }
-}
-
-//
-// ExtensionActionStorageManager
-//
-
-ExtensionActionStorageManager::ExtensionActionStorageManager(Profile* profile)
-    : profile_(profile) {
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
-                 content::Source<Profile>(profile_));
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-
-  StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
-  if (storage)
-    storage->RegisterKey(kBrowserActionStorageKey);
-}
-
-ExtensionActionStorageManager::~ExtensionActionStorageManager() {
-}
-
-void ExtensionActionStorageManager::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_EXTENSION_LOADED: {
-      const Extension* extension =
-          content::Details<const Extension>(details).ptr();
-      if (!ExtensionActionManager::Get(profile_)->
-          GetBrowserAction(*extension)) {
-        break;
-      }
-
-      StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
-      if (storage) {
-        storage->GetExtensionValue(extension->id(), kBrowserActionStorageKey,
-            base::Bind(&ExtensionActionStorageManager::ReadFromStorage,
-                       AsWeakPtr(), extension->id()));
-      }
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED: {
-      ExtensionAction* extension_action =
-          content::Source<ExtensionAction>(source).ptr();
-      Profile* profile = content::Details<Profile>(details).ptr();
-      if (profile != profile_)
-        break;
-
-      extension_action->set_has_changed(true);
-      WriteToStorage(extension_action);
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
+    DispatchEventToExtension(
+        web_contents->GetBrowserContext(),
+        extension_action.extension_id(),
+        event_name,
+        args.Pass());
   }
 }
 
-void ExtensionActionStorageManager::WriteToStorage(
-    ExtensionAction* extension_action) {
-  StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
-  if (!storage)
-    return;
-
-  scoped_ptr<base::DictionaryValue> defaults =
-      DefaultsToValue(extension_action);
-  storage->SetExtensionValue(extension_action->extension_id(),
-                             kBrowserActionStorageKey,
-                             defaults.PassAs<base::Value>());
-}
-
-void ExtensionActionStorageManager::ReadFromStorage(
-    const std::string& extension_id, scoped_ptr<base::Value> value) {
-  const Extension* extension =
-      ExtensionSystem::Get(profile_)->extension_service()->
-      extensions()->GetByID(extension_id);
-  if (!extension)
+void ExtensionActionAPI::NotifyPageActionsChanged(
+    content::WebContents* web_contents) {
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  if (!browser)
     return;
-
-  ExtensionAction* browser_action =
-      ExtensionActionManager::Get(profile_)->GetBrowserAction(*extension);
-  CHECK(browser_action);
-
-  // Don't load values from storage if the extension has updated a value
-  // already. The extension may have only updated some of the values, but
-  // this is a good first approximation. If the extension is doing stuff
-  // to the browser action, we can assume it is ready to take over.
-  if (browser_action->has_changed())
+  LocationBar* location_bar =
+      browser->window() ? browser->window()->GetLocationBar() : NULL;
+  if (!location_bar)
     return;
+  location_bar->UpdatePageActions();
 
-  const base::DictionaryValue* dict = NULL;
-  if (!value.get() || !value->GetAsDictionary(&dict))
-    return;
+  FOR_EACH_OBSERVER(Observer, observers_, OnPageActionsUpdated(web_contents));
+}
 
-  SetDefaultsFromValue(dict, browser_action);
+void ExtensionActionAPI::Shutdown() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnExtensionActionAPIShuttingDown());
 }
 
 //
@@ -493,17 +360,14 @@ ExtensionActionFunction::ExtensionActionFunction()
 ExtensionActionFunction::~ExtensionActionFunction() {
 }
 
-bool ExtensionActionFunction::RunImpl() {
+bool ExtensionActionFunction::RunSync() {
   ExtensionActionManager* manager = ExtensionActionManager::Get(GetProfile());
-  const Extension* extension = GetExtension();
-  if (StartsWithASCII(name(), "scriptBadge.", false)) {
-    extension_action_ = manager->GetScriptBadge(*extension);
-  } else if (StartsWithASCII(name(), "systemIndicator.", false)) {
-    extension_action_ = manager->GetSystemIndicator(*extension);
+  if (StartsWithASCII(name(), "systemIndicator.", false)) {
+    extension_action_ = manager->GetSystemIndicator(*extension());
   } else {
-    extension_action_ = manager->GetBrowserAction(*extension);
+    extension_action_ = manager->GetBrowserAction(*extension());
     if (!extension_action_) {
-      extension_action_ = manager->GetPageAction(*extension);
+      extension_action_ = manager->GetPageAction(*extension());
     }
   }
   if (!extension_action_) {
@@ -551,21 +415,21 @@ bool ExtensionActionFunction::ExtractDataFromArguments() {
     return true;
 
   switch (first_arg->GetType()) {
-    case Value::TYPE_INTEGER:
+    case base::Value::TYPE_INTEGER:
       CHECK(first_arg->GetAsInteger(&tab_id_));
       break;
 
-    case Value::TYPE_DICTIONARY: {
+    case base::Value::TYPE_DICTIONARY: {
       // Found the details argument.
       details_ = static_cast<base::DictionaryValue*>(first_arg);
       // Still need to check for the tabId within details.
       base::Value* tab_id_value = NULL;
       if (details_->Get("tabId", &tab_id_value)) {
         switch (tab_id_value->GetType()) {
-          case Value::TYPE_NULL:
+          case base::Value::TYPE_NULL:
             // OK; tabId is optional, leave it default.
             return true;
-          case Value::TYPE_INTEGER:
+          case base::Value::TYPE_INTEGER:
             CHECK(tab_id_value->GetAsInteger(&tab_id_));
             return true;
           default:
@@ -577,7 +441,7 @@ bool ExtensionActionFunction::ExtractDataFromArguments() {
       break;
     }
 
-    case Value::TYPE_NULL:
+    case base::Value::TYPE_NULL:
       // The tabId might be an optional argument.
       break;
 
@@ -589,97 +453,18 @@ bool ExtensionActionFunction::ExtractDataFromArguments() {
 }
 
 void ExtensionActionFunction::NotifyChange() {
-  switch (extension_action_->action_type()) {
-    case ActionInfo::TYPE_BROWSER:
-    case ActionInfo::TYPE_PAGE:
-      if (ExtensionActionManager::Get(GetProfile())
-              ->GetBrowserAction(*extension_.get())) {
-        NotifyBrowserActionChange();
-      } else if (ExtensionActionManager::Get(GetProfile())
-                     ->GetPageAction(*extension_.get())) {
-        NotifyLocationBarChange();
-      }
-      return;
-    case ActionInfo::TYPE_SCRIPT_BADGE:
-      NotifyLocationBarChange();
-      return;
-    case ActionInfo::TYPE_SYSTEM_INDICATOR:
-      NotifySystemIndicatorChange();
-      return;
-  }
-  NOTREACHED();
-}
-
-void ExtensionActionFunction::NotifyBrowserActionChange() {
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
-      content::Source<ExtensionAction>(extension_action_),
-      content::Details<Profile>(GetProfile()));
-}
-
-void ExtensionActionFunction::NotifyLocationBarChange() {
-  TabHelper::FromWebContents(contents_)->
-      location_bar_controller()->NotifyChange();
-}
-
-void ExtensionActionFunction::NotifySystemIndicatorChange() {
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED,
-      content::Source<Profile>(GetProfile()),
-      content::Details<ExtensionAction>(extension_action_));
-}
-
-// static
-bool ExtensionActionFunction::ParseCSSColorString(
-    const std::string& color_string,
-    SkColor* result) {
-  std::string formatted_color = "#";
-  // Check the string for incorrect formatting.
-  if (color_string[0] != '#')
-    return false;
-
-  // Convert the string from #FFF format to #FFFFFF format.
-  if (color_string.length() == 4) {
-    for (size_t i = 1; i < color_string.length(); i++) {
-      formatted_color += color_string[i];
-      formatted_color += color_string[i];
-    }
-  } else {
-    formatted_color = color_string;
-  }
-
-  if (formatted_color.length() != 7)
-    return false;
-
-  // Convert the string to an integer and make sure it is in the correct value
-  // range.
-  int color_ints[3] = {0};
-  for (int i = 0; i < 3; i++) {
-    if (!base::HexStringToInt(formatted_color.substr(1 + (2 * i), 2),
-                              color_ints + i))
-      return false;
-    if (color_ints[i] > 255 || color_ints[i] < 0)
-      return false;
-  }
-
-  *result = SkColorSetARGB(255, color_ints[0], color_ints[1], color_ints[2]);
-  return true;
+  ExtensionActionAPI::Get(GetProfile())->NotifyChange(
+      extension_action_, contents_, GetProfile());
 }
 
 bool ExtensionActionFunction::SetVisible(bool visible) {
   if (extension_action_->GetIsVisible(tab_id_) == visible)
     return true;
-  extension_action_->SetAppearance(
-      tab_id_, visible ? ExtensionAction::ACTIVE : ExtensionAction::INVISIBLE);
+  extension_action_->SetIsVisible(tab_id_, visible);
   NotifyChange();
   return true;
 }
 
-TabHelper& ExtensionActionFunction::tab_helper() const {
-  CHECK(contents_);
-  return *TabHelper::FromWebContents(contents_);
-}
-
 bool ExtensionActionShowFunction::RunExtensionAction() {
   return SetVisible(true);
 }
@@ -697,19 +482,9 @@ bool ExtensionActionSetIconFunction::RunExtensionAction() {
   int icon_index;
   if (details_->GetDictionary("imageData", &canvas_set)) {
     gfx::ImageSkia icon;
-    // Extract icon representations from the ImageDataSet dictionary.
-    for (size_t i = 0; i < arraysize(kIconSizes); i++) {
-      base::BinaryValue* binary;
-      if (canvas_set->GetBinary(kIconSizes[i].size_string, &binary)) {
-        IPC::Message pickle(binary->GetBuffer(), binary->GetSize());
-        PickleIterator iter(pickle);
-        SkBitmap bitmap;
-        EXTENSION_FUNCTION_VALIDATE(IPC::ReadParam(&pickle, &iter, &bitmap));
-        CHECK(!bitmap.isNull());
-        float scale = ui::GetImageScale(kIconSizes[i].scale);
-        icon.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
-      }
-    }
+
+    EXTENSION_FUNCTION_VALIDATE(
+        ExtensionAction::ParseIconFromCanvasDictionary(*canvas_set, &icon));
 
     extension_action_->SetIcon(tab_id_, gfx::Image(icon));
   } else if (details_->GetInteger("iconIndex", &icon_index)) {
@@ -738,7 +513,7 @@ bool ExtensionActionSetPopupFunction::RunExtensionAction() {
 
   GURL popup_url;
   if (!popup_string.empty())
-    popup_url = GetExtension()->GetResourceURL(popup_string);
+    popup_url = extension()->GetResourceURL(popup_string);
 
   extension_action_->SetPopupUrl(tab_id_, popup_url);
   NotifyChange();
@@ -756,10 +531,10 @@ bool ExtensionActionSetBadgeTextFunction::RunExtensionAction() {
 
 bool ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() {
   EXTENSION_FUNCTION_VALIDATE(details_);
-  Value* color_value = NULL;
+  base::Value* color_value = NULL;
   EXTENSION_FUNCTION_VALIDATE(details_->Get("color", &color_value));
   SkColor color = 0;
-  if (color_value->IsType(Value::TYPE_LIST)) {
+  if (color_value->IsType(base::Value::TYPE_LIST)) {
     base::ListValue* list = NULL;
     EXTENSION_FUNCTION_VALIDATE(details_->GetList("color", &list));
     EXTENSION_FUNCTION_VALIDATE(list->GetSize() == 4);
@@ -771,10 +546,10 @@ bool ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() {
 
     color = SkColorSetARGB(color_array[3], color_array[0],
                            color_array[1], color_array[2]);
-  } else if (color_value->IsType(Value::TYPE_STRING)) {
+  } else if (color_value->IsType(base::Value::TYPE_STRING)) {
     std::string color_string;
     EXTENSION_FUNCTION_VALIDATE(details_->GetString("color", &color_string));
-    if (!ParseCSSColorString(color_string, &color))
+    if (!image_util::ParseCSSColorString(color_string, &color))
       return false;
   }
 
@@ -818,22 +593,26 @@ BrowserActionOpenPopupFunction::BrowserActionOpenPopupFunction()
     : response_sent_(false) {
 }
 
-bool BrowserActionOpenPopupFunction::RunImpl() {
-  ExtensionToolbarModel* model = extensions::ExtensionSystem::Get(GetProfile())
-                                     ->extension_service()
-                                     ->toolbar_model();
-  if (!model) {
-    error_ = kInternalError;
-    return false;
-  }
-
-  if (!model->ShowBrowserActionPopup(extension_)) {
+bool BrowserActionOpenPopupFunction::RunAsync() {
+  // We only allow the popup in the active window.
+  Browser* browser = chrome::FindLastActiveWithProfile(
+                         GetProfile(), chrome::GetActiveDesktop());
+
+  // If there's no active browser, or the Toolbar isn't visible, abort.
+  // Otherwise, try to open a popup in the active browser.
+  // TODO(justinlin): Remove toolbar check when http://crbug.com/308645 is
+  // fixed.
+  if (!browser ||
+      !browser->window()->IsActive() ||
+      !browser->window()->IsToolbarVisible() ||
+      !ExtensionActionAPI::Get(GetProfile())->ShowExtensionActionPopup(
+          extension_.get(), browser, false)) {
     error_ = kOpenPopupError;
     return false;
   }
 
   registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
+                 NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
                  content::Source<Profile>(GetProfile()));
 
   // Set a timeout for waiting for the notification that the popup is loaded.
@@ -861,7 +640,7 @@ void BrowserActionOpenPopupFunction::Observe(
     int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, type);
+  DCHECK_EQ(NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, type);
   if (response_sent_)
     return;
 
@@ -875,88 +654,4 @@ void BrowserActionOpenPopupFunction::Observe(
   registrar_.RemoveAll();
 }
 
-//
-// ScriptBadgeGetAttentionFunction
-//
-
-ScriptBadgeGetAttentionFunction::~ScriptBadgeGetAttentionFunction() {}
-
-bool ScriptBadgeGetAttentionFunction::RunExtensionAction() {
-  tab_helper().location_bar_controller()->GetAttentionFor(extension_id());
-  return true;
-}
-
 }  // namespace extensions
-
-//
-// PageActionsFunction (deprecated)
-//
-
-PageActionsFunction::PageActionsFunction() {
-}
-
-PageActionsFunction::~PageActionsFunction() {
-}
-
-bool PageActionsFunction::SetPageActionEnabled(bool enable) {
-  std::string extension_action_id;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_action_id));
-  DictionaryValue* action = NULL;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &action));
-
-  int tab_id;
-  EXTENSION_FUNCTION_VALIDATE(action->GetInteger(
-      page_actions_keys::kTabIdKey, &tab_id));
-  std::string url;
-  EXTENSION_FUNCTION_VALIDATE(action->GetString(
-      page_actions_keys::kUrlKey, &url));
-
-  std::string title;
-  if (enable) {
-    if (action->HasKey(page_actions_keys::kTitleKey))
-      EXTENSION_FUNCTION_VALIDATE(action->GetString(
-          page_actions_keys::kTitleKey, &title));
-  }
-
-  ExtensionAction* page_action = extensions::ExtensionActionManager::Get(
-      GetProfile())->GetPageAction(*GetExtension());
-  if (!page_action) {
-    error_ = extensions::kNoPageActionError;
-    return false;
-  }
-
-  // Find the WebContents that contains this tab id.
-  WebContents* contents = NULL;
-  bool result = ExtensionTabUtil::GetTabById(
-      tab_id, GetProfile(), include_incognito(), NULL, NULL, &contents, NULL);
-  if (!result || !contents) {
-    error_ = extensions::ErrorUtils::FormatErrorMessage(
-        extensions::kNoTabError, base::IntToString(tab_id));
-    return false;
-  }
-
-  // Make sure the URL hasn't changed.
-  content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
-  if (!entry || url != entry->GetURL().spec()) {
-    error_ = extensions::ErrorUtils::FormatErrorMessage(
-        extensions::kUrlNotActiveError, url);
-    return false;
-  }
-
-  // Set visibility and broadcast notifications that the UI should be updated.
-  page_action->SetAppearance(
-      tab_id, enable ? ExtensionAction::ACTIVE : ExtensionAction::INVISIBLE);
-  page_action->SetTitle(tab_id, title);
-  extensions::TabHelper::FromWebContents(contents)->
-      location_bar_controller()->NotifyChange();
-
-  return true;
-}
-
-bool EnablePageActionsFunction::RunImpl() {
-  return SetPageActionEnabled(true);
-}
-
-bool DisablePageActionsFunction::RunImpl() {
-  return SetPageActionEnabled(false);
-}