12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/declarative_content/content_action.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <map> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h" 105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/declarative_content/content_constants.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_action.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_action_manager.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/invalidate_type.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace keys = declarative_content_constants; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Error messages. 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInvalidInstanceTypeError[] = 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "An action has an invalid instanceType: %s"; 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define INPUT_FORMAT_VALIDATE(test) do { \ 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!(test)) { \ 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *bad_message = true; \ 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return scoped_refptr<ContentAction>(NULL); \ 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } \ 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (0) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The following are concrete actions. 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Action that instructs to show an extension's page action. 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ShowPageAction : public ContentAction { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShowPageAction() {} 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Implementation of ContentAction: 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual Type GetType() const OVERRIDE { return ACTION_SHOW_PAGE_ACTION; } 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void Apply(const std::string& extension_id, 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Time& extension_install_time, 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ApplyInfo* apply_info) const OVERRIDE { 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetPageAction(apply_info->profile, extension_id)->DeclarativeShow( 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionTabUtil::GetTabId(apply_info->tab)); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apply_info->tab->NotifyNavigationStateChanged( 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::INVALIDATE_TYPE_PAGE_ACTIONS); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void Revert(const std::string& extension_id, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Time& extension_install_time, 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ApplyInfo* apply_info) const OVERRIDE { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetPageAction(apply_info->profile, extension_id)-> 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UndoDeclarativeShow(ExtensionTabUtil::GetTabId(apply_info->tab)); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) apply_info->tab->NotifyNavigationStateChanged( 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::INVALIDATE_TYPE_PAGE_ACTIONS); 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static ExtensionAction* GetPageAction(Profile* profile, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& extension_id) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionService* service = 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionSystem::Get(profile)->extension_service(); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = service->GetInstalledExtension(extension_id); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(extension); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ExtensionActionManager::Get(profile)->GetPageAction(*extension); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual ~ShowPageAction() {} 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ShowPageAction); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Helper function for ContentActions that can be instantiated by just 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// calling the constructor. 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <class T> 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)scoped_refptr<ContentAction> CallConstructorFactoryMethod( 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::DictionaryValue* dict, 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* error, 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* bad_message) { 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return scoped_refptr<ContentAction>(new T); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct ContentActionFactory { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Factory methods for ContentAction instances. |dict| contains the json 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // dictionary that describes the action. |error| is used to return error 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // messages in case the extension passed an action that was syntactically 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // correct but semantically incorrect. |bad_message| is set to true in case 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |dict| does not confirm to the validated JSON specification. 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) typedef scoped_refptr<ContentAction> 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (* FactoryMethod)(const base::DictionaryValue* /* dict */, 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* /* error */, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* /* bad_message */); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Maps the name of a declarativeContent action type to the factory 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // function creating it. 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<std::string, FactoryMethod> factory_methods; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ContentActionFactory() { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) factory_methods[keys::kShowPageAction] = 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &CallConstructorFactoryMethod<ShowPageAction>; 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::LazyInstance<ContentActionFactory>::Leaky 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_content_action_factory = LAZY_INSTANCE_INITIALIZER; 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ContentAction 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContentAction::ContentAction() {} 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContentAction::~ContentAction() {} 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)scoped_refptr<ContentAction> ContentAction::Create( 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Value& json_action, 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* error, 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* bad_message) { 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ""; 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *bad_message = false; 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::DictionaryValue* action_dict = NULL; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict)); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string instance_type; 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) INPUT_FORMAT_VALIDATE( 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) action_dict->GetString(keys::kInstanceType, &instance_type)); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ContentActionFactory& factory = g_content_action_factory.Get(); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<std::string, ContentActionFactory::FactoryMethod>::iterator 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) factory_method_iter = factory.factory_methods.find(instance_type); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (factory_method_iter != factory.factory_methods.end()) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (*factory_method_iter->second)(action_dict, error, bad_message); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str()); 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return scoped_refptr<ContentAction>(); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace extensions 149