| Index: chrome/browser/extensions/api/extension_action/extension_actions_api.cc
|
| diff --git a/chrome/browser/extensions/api/extension_action/extension_actions_api.cc b/chrome/browser/extensions/api/extension_action/extension_actions_api.cc
|
| index 975fc6f72d8163ba9f0be37807f90050705dd97b..44ea5d4b38eb46f068a2293eaf02ca7296d7001c 100644
|
| --- a/chrome/browser/extensions/api/extension_action/extension_actions_api.cc
|
| +++ b/chrome/browser/extensions/api/extension_action/extension_actions_api.cc
|
| @@ -6,14 +6,17 @@
|
|
|
| #include <string>
|
|
|
| +#include "base/base64.h"
|
| #include "base/string_number_conversions.h"
|
| #include "base/string_piece.h"
|
| #include "base/values.h"
|
| #include "chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h"
|
| #include "chrome/browser/extensions/extension_service.h"
|
| -#include "chrome/browser/extensions/tab_helper.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/tab_helper.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/ui/tab_contents/tab_contents.h"
|
| #include "chrome/common/chrome_notification_types.h"
|
| @@ -26,14 +29,209 @@
|
|
|
| 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";
|
| +
|
| // Errors.
|
| const char kNoExtensionActionError[] =
|
| "This extension has no action specified.";
|
| const char kNoTabError[] = "No tab with id: *.";
|
| const char kIconIndexOutOfBounds[] = "Page action icon index out of bounds.";
|
|
|
| +// 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 ImageToString(const gfx::Image& image) {
|
| + IPC::Message bitmap_pickle;
|
| + IPC::WriteParam(&bitmap_pickle, image.AsBitmap());
|
| + 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;
|
| +
|
| + 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));
|
| + if (dict->GetString(kIconStorageKey, &str_value) &&
|
| + StringToSkBitmap(str_value, &bitmap))
|
| + action->SetIcon(kTabId, bitmap);
|
| +}
|
| +
|
| +// 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 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);
|
| + dict->SetString(kIconStorageKey, ImageToString(action->GetIcon(kTabId)));
|
| +
|
| + return dict.Pass();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace extensions {
|
| +
|
| +//
|
| +// 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 (!extension->browser_action())
|
| + 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;
|
| + }
|
| +}
|
| +
|
| +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()->
|
| + GetExtensionById(extension_id, true);
|
| + if (!extension)
|
| + return;
|
| +
|
| + CHECK(extension->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 (extension->browser_action()->has_changed())
|
| + return;
|
| +
|
| + base::DictionaryValue* dict = NULL;
|
| + if (!value.get() || !value->GetAsDictionary(&dict))
|
| + return;
|
| +
|
| + SetDefaultsFromValue(dict, extension->browser_action());
|
| +}
|
| +
|
| +} // namespace extensions
|
| +
|
| +
|
| +//
|
| +// ExtensionActionFunction
|
| +//
|
| +
|
| ExtensionActionFunction::ExtensionActionFunction()
|
| : details_(NULL),
|
| tab_id_(ExtensionAction::kDefaultTabId),
|
| @@ -137,7 +335,7 @@ void ExtensionActionFunction::NotifyBrowserActionChange() {
|
| content::NotificationService::current()->Notify(
|
| chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
|
| content::Source<ExtensionAction>(extension_action_),
|
| - content::NotificationService::NoDetails());
|
| + content::Details<Profile>(profile()));
|
| }
|
|
|
| void ExtensionActionFunction::NotifyLocationBarChange() {
|
| @@ -210,8 +408,7 @@ bool ExtensionActionSetIconFunction::RunExtensionAction() {
|
| IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize());
|
| PickleIterator iter(bitmap_pickle);
|
| SkBitmap bitmap;
|
| - EXTENSION_FUNCTION_VALIDATE(
|
| - IPC::ReadParam(&bitmap_pickle, &iter, &bitmap));
|
| + EXTENSION_FUNCTION_VALIDATE(IPC::ReadParam(&bitmap_pickle, &iter, &bitmap));
|
| extension_action_->SetIcon(tab_id_, bitmap);
|
| } else if (details_->GetInteger("iconIndex", &icon_index)) {
|
| // If --enable-script-badges is on there might legitimately be an iconIndex
|
|
|