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