Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / management / management_api.cc
index 35fd8ca..f2cf45f 100644 (file)
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/extensions/api/management/management_api.h"
 
-#include <map>
 #include <string>
 #include <vector>
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/management/management_api_constants.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/launch_util.h"
+#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
-#include "chrome/common/chrome_utility_messages.h"
+#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
 #include "chrome/common/extensions/api/management.h"
+#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
 #include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
 #include "extensions/browser/management_policy.h"
+#include "extensions/browser/uninstall_reason.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_icon_set.h"
+#include "extensions/common/manifest_handlers/icons_handler.h"
 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
+#include "extensions/common/manifest_handlers/options_page_info.h"
 #include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_data.h"
 #include "extensions/common/url_pattern.h"
 
-#if !defined(OS_ANDROID)
-#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
-#endif
-
 using base::IntToString;
 using content::BrowserThread;
 using content::UtilityProcessHost;
@@ -81,7 +84,7 @@ AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
 std::vector<std::string> CreateWarningsList(const Extension* extension) {
   std::vector<std::string> warnings_list;
   PermissionMessages warnings =
-      PermissionsData::GetPermissionMessages(extension);
+      extension->permissions_data()->GetPermissionMessages();
   for (PermissionMessages::const_iterator iter = warnings.begin();
        iter != warnings.end(); ++iter) {
     warnings_list.push_back(base::UTF16ToUTF8(iter->message()));
@@ -90,6 +93,27 @@ std::vector<std::string> CreateWarningsList(const Extension* extension) {
   return warnings_list;
 }
 
+std::vector<management::LaunchType> GetAvailableLaunchTypes(
+    const Extension& extension) {
+  std::vector<management::LaunchType> launch_type_list;
+  if (extension.is_platform_app()) {
+    launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
+    return launch_type_list;
+  }
+
+  launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
+
+#if !defined(OS_MACOSX)
+  launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
+#endif
+
+  if (!util::IsStreamlinedHostedAppsEnabled()) {
+    launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB);
+    launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN);
+  }
+  return launch_type_list;
+}
+
 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
     const Extension& extension,
     ExtensionSystem* system) {
@@ -103,7 +127,7 @@ scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
   info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
   info->version = extension.VersionString();
   info->description = extension.description();
-  info->options_url = ManifestURL::GetOptionsPage(&extension).spec();
+  info->options_url = OptionsPageInfo::GetOptionsPage(&extension).spec();
   info->homepage_url.reset(new std::string(
       ManifestURL::GetHomepageURL(&extension).spec()));
   info->may_disable = system->management_policy()->
@@ -125,7 +149,7 @@ scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
   if (info->enabled) {
     info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE;
   } else {
-    ExtensionPrefs* prefs = service->extension_prefs();
+    ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
     if (prefs->DidExtensionEscalatePermissions(extension.id())) {
       info->disabled_reason =
           management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE;
@@ -162,7 +186,7 @@ scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
   }
 
   const std::set<std::string> perms =
-      extension.GetActivePermissions()->GetAPIsAsStrings();
+      extension.permissions_data()->active_permissions()->GetAPIsAsStrings();
   if (!perms.empty()) {
     std::set<std::string>::const_iterator perms_iter;
     for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
@@ -172,7 +196,7 @@ scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
   if (!extension.is_hosted_app()) {
     // Skip host permissions for hosted apps.
     const URLPatternSet host_perms =
-        extension.GetActivePermissions()->explicit_hosts();
+        extension.permissions_data()->active_permissions()->explicit_hosts();
     if (!host_perms.is_empty()) {
       for (URLPatternSet::const_iterator iter = host_perms.begin();
            iter != host_perms.end(); ++iter) {
@@ -207,17 +231,50 @@ scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
       break;
   }
 
+  info->launch_type = management::LAUNCH_TYPE_NONE;
+  if (extension.is_app()) {
+    LaunchType launch_type;
+    if (extension.is_platform_app()) {
+      launch_type = LAUNCH_TYPE_WINDOW;
+    } else {
+      launch_type =
+          GetLaunchType(ExtensionPrefs::Get(service->profile()), &extension);
+    }
+
+    switch (launch_type) {
+      case LAUNCH_TYPE_PINNED:
+        info->launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
+        break;
+      case LAUNCH_TYPE_REGULAR:
+        info->launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
+        break;
+      case LAUNCH_TYPE_FULLSCREEN:
+        info->launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
+        break;
+      case LAUNCH_TYPE_WINDOW:
+        info->launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
+        break;
+      case LAUNCH_TYPE_INVALID:
+      case NUM_LAUNCH_TYPES:
+        NOTREACHED();
+    }
+
+    info->available_launch_types.reset(new std::vector<management::LaunchType>(
+        GetAvailableLaunchTypes(extension)));
+  }
+
   return info.Pass();
 }
 
 void AddExtensionInfo(const ExtensionSet& extensions,
                             ExtensionSystem* system,
-                            ExtensionInfoList* extension_list) {
+                            ExtensionInfoList* extension_list,
+                            content::BrowserContext* context) {
   for (ExtensionSet::const_iterator iter = extensions.begin();
        iter != extensions.end(); ++iter) {
     const Extension& extension = *iter->get();
 
-    if (extension.ShouldNotBeVisible())
+    if (ui_util::ShouldNotBeVisible(&extension, context))
       continue;  // Skip built-in extensions/apps.
 
     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
@@ -225,30 +282,33 @@ void AddExtensionInfo(const ExtensionSet& extensions,
   }
 }
 
-} // namespace
+}  // namespace
 
 ExtensionService* ManagementFunction::service() {
-  return GetProfile()->GetExtensionService();
+  return ExtensionSystem::Get(GetProfile())->extension_service();
 }
 
 ExtensionService* AsyncManagementFunction::service() {
-  return GetProfile()->GetExtensionService();
+  return ExtensionSystem::Get(GetProfile())->extension_service();
 }
 
-bool ManagementGetAllFunction::RunImpl() {
+bool ManagementGetAllFunction::RunSync() {
   ExtensionInfoList extensions;
   ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
 
-  AddExtensionInfo(registry->enabled_extensions(), system, &extensions);
-  AddExtensionInfo(registry->disabled_extensions(), system, &extensions);
-  AddExtensionInfo(registry->terminated_extensions(), system, &extensions);
+  AddExtensionInfo(registry->enabled_extensions(),
+                   system, &extensions, browser_context());
+  AddExtensionInfo(registry->disabled_extensions(),
+                   system, &extensions, browser_context());
+  AddExtensionInfo(registry->terminated_extensions(),
+                   system, &extensions, browser_context());
 
   results_ = management::GetAll::Results::Create(extensions);
   return true;
 }
 
-bool ManagementGetFunction::RunImpl() {
+bool ManagementGetFunction::RunSync() {
   scoped_ptr<management::Get::Params> params(
       management::Get::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -267,7 +327,15 @@ bool ManagementGetFunction::RunImpl() {
   return true;
 }
 
-bool ManagementGetPermissionWarningsByIdFunction::RunImpl() {
+bool ManagementGetSelfFunction::RunSync() {
+  scoped_ptr<management::ExtensionInfo> info =
+      CreateExtensionInfo(*extension_, ExtensionSystem::Get(GetProfile()));
+  results_ = management::Get::Results::Create(*info);
+
+  return true;
+}
+
+bool ManagementGetPermissionWarningsByIdFunction::RunSync() {
   scoped_ptr<management::GetPermissionWarningsById::Params> params(
       management::GetPermissionWarningsById::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -373,7 +441,7 @@ class SafeManifestJSONParser : public UtilityProcessHostClient {
 
 }  // namespace
 
-bool ManagementGetPermissionWarningsByManifestFunction::RunImpl() {
+bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() {
   scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
       management::GetPermissionWarningsByManifest::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -406,7 +474,7 @@ void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
       management::GetPermissionWarningsByManifest::Results::Create(warnings);
   SendResponse(true);
 
-  // Matched with AddRef() in RunImpl().
+  // Matched with AddRef() in RunAsync().
   Release();
 }
 
@@ -415,11 +483,11 @@ void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
   error_ = error;
   SendResponse(false);
 
-  // Matched with AddRef() in RunImpl().
+  // Matched with AddRef() in RunAsync().
   Release();
 }
 
-bool ManagementLaunchAppFunction::RunImpl() {
+bool ManagementLaunchAppFunction::RunSync() {
   scoped_ptr<management::LaunchApp::Params> params(
       management::LaunchApp::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -439,14 +507,12 @@ bool ManagementLaunchAppFunction::RunImpl() {
   // If the user has not set a preference, the default launch value will be
   // returned.
   LaunchContainer launch_container =
-      GetLaunchContainer(service()->extension_prefs(), extension);
+      GetLaunchContainer(ExtensionPrefs::Get(GetProfile()), extension);
   OpenApplication(AppLaunchParams(
       GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
-#if !defined(OS_ANDROID)
   CoreAppLauncherHandler::RecordAppLaunchType(
       extension_misc::APP_LAUNCH_EXTENSION_API,
       extension->GetType());
-#endif
 
   return true;
 }
@@ -457,15 +523,17 @@ ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
 }
 
-bool ManagementSetEnabledFunction::RunImpl() {
+bool ManagementSetEnabledFunction::RunAsync() {
   scoped_ptr<management::SetEnabled::Params> params(
       management::SetEnabled::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   extension_id_ = params->id;
 
-  const Extension* extension = service()->GetInstalledExtension(extension_id_);
-  if (!extension || extension->ShouldNotBeVisible()) {
+  const Extension* extension =
+      ExtensionRegistry::Get(GetProfile())
+          ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
+  if (!extension || ui_util::ShouldNotBeVisible(extension, browser_context())) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kNoExtensionError, extension_id_);
     return false;
@@ -484,13 +552,13 @@ bool ManagementSetEnabledFunction::RunImpl() {
   bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
 
   if (!currently_enabled && params->enabled) {
-    ExtensionPrefs* prefs = service()->extension_prefs();
+    ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
     if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
       if (!user_gesture()) {
         error_ = keys::kGestureNeededForEscalationError;
         return false;
       }
-      AddRef(); // Matched in InstallUIProceed/InstallUIAbort
+      AddRef();  // Matched in InstallUIProceed/InstallUIAbort
       install_prompt_.reset(
           new ExtensionInstallPrompt(GetAssociatedWebContents()));
       install_prompt_->ConfirmReEnable(this, extension);
@@ -528,11 +596,14 @@ ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
 }
 
 bool ManagementUninstallFunctionBase::Uninstall(
-    const std::string& extension_id,
+    const std::string& target_extension_id,
     bool show_confirm_dialog) {
-  extension_id_ = extension_id;
-  const Extension* extension = service()->GetExtensionById(extension_id_, true);
-  if (!extension || extension->ShouldNotBeVisible()) {
+  extension_id_ = target_extension_id;
+  const Extension* target_extension =
+      extensions::ExtensionRegistry::Get(browser_context())->
+          GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
+  if (!target_extension ||
+      ui_util::ShouldNotBeVisible(target_extension, browser_context())) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kNoExtensionError, extension_id_);
     return false;
@@ -540,7 +611,7 @@ bool ManagementUninstallFunctionBase::Uninstall(
 
   if (!ExtensionSystem::Get(GetProfile())
            ->management_policy()
-           ->UserMayModifySettings(extension, NULL)) {
+           ->UserMayModifySettings(target_extension, NULL)) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kUserCantModifyError, extension_id_);
     return false;
@@ -548,10 +619,19 @@ bool ManagementUninstallFunctionBase::Uninstall(
 
   if (auto_confirm_for_test == DO_NOT_SKIP) {
     if (show_confirm_dialog) {
-      AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
+      AddRef();  // Balanced in ExtensionUninstallAccepted/Canceled
+      extensions::WindowController* controller = GetExtensionWindowController();
       extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
-          GetProfile(), GetCurrentBrowser(), this));
-      extension_uninstall_dialog_->ConfirmUninstall(extension);
+          GetProfile(),
+          controller ? controller->window()->GetNativeWindow() : NULL,
+          this));
+      if (extension_id() != target_extension_id) {
+        extension_uninstall_dialog_->ConfirmProgrammaticUninstall(
+            target_extension, extension());
+      } else {
+        // If this is a self uninstall, show the generic uninstall dialog.
+        extension_uninstall_dialog_->ConfirmUninstall(target_extension);
+      }
     } else {
       Finish(true);
     }
@@ -570,19 +650,30 @@ void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
 
 void ManagementUninstallFunctionBase::Finish(bool should_uninstall) {
   if (should_uninstall) {
-    bool success = service()->UninstallExtension(
-        extension_id_,
-        false, /* external uninstall */
-        NULL);
+    // The extension can be uninstalled in another window while the UI was
+    // showing. Do nothing in that case.
+    ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
+    const Extension* extension = registry->GetExtensionById(
+        extension_id_, ExtensionRegistry::EVERYTHING);
+    if (!extension) {
+      error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
+                                              extension_id_);
+      SendResponse(false);
+    } else {
+      bool success = service()->UninstallExtension(
+          extension_id_,
+          extensions::UNINSTALL_REASON_MANAGEMENT_API,
+          base::Bind(&base::DoNothing),
+          NULL);
 
-    // TODO set error_ if !success
-    SendResponse(success);
+      // TODO set error_ if !success
+      SendResponse(success);
+    }
   } else {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kUninstallCanceledError, extension_id_);
     SendResponse(false);
   }
-
 }
 
 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
@@ -601,10 +692,10 @@ ManagementUninstallFunction::ManagementUninstallFunction() {
 ManagementUninstallFunction::~ManagementUninstallFunction() {
 }
 
-bool ManagementUninstallFunction::RunImpl() {
+bool ManagementUninstallFunction::RunAsync() {
   scoped_ptr<management::Uninstall::Params> params(
       management::Uninstall::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(extension_);
+  EXTENSION_FUNCTION_VALIDATE(extension_.get());
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   bool show_confirm_dialog = true;
@@ -628,7 +719,7 @@ ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
 }
 
-bool ManagementUninstallSelfFunction::RunImpl() {
+bool ManagementUninstallSelfFunction::RunAsync() {
   scoped_ptr<management::UninstallSelf::Params> params(
       management::UninstallSelf::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -639,107 +730,295 @@ bool ManagementUninstallSelfFunction::RunImpl() {
   return Uninstall(extension_->id(), show_confirm_dialog);
 }
 
-ManagementEventRouter::ManagementEventRouter(Profile* profile)
-    : profile_(profile) {
-  int types[] = {
-    chrome::NOTIFICATION_EXTENSION_INSTALLED,
-    chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
-    chrome::NOTIFICATION_EXTENSION_LOADED,
-    chrome::NOTIFICATION_EXTENSION_UNLOADED
-  };
+ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
+}
+
+ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
+}
+
+// static
+void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
+    bool should_proceed) {
+  auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
+}
+
+void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
+  if (!created)
+    error_ = keys::kCreateShortcutCanceledError;
+  SendResponse(created);
+  Release();
+}
+
+bool ManagementCreateAppShortcutFunction::RunAsync() {
+  if (!user_gesture()) {
+    error_ = keys::kGestureNeededForCreateAppShortcutError;
+    return false;
+  }
+
+  scoped_ptr<management::CreateAppShortcut::Params> params(
+      management::CreateAppShortcut::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+  const Extension* extension = service()->GetExtensionById(params->id, true);
+  if (!extension) {
+    error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
+                                            params->id);
+    return false;
+  }
+
+  if (!extension->is_app()) {
+    error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
+    return false;
+  }
 
-  CHECK(registrar_.IsEmpty());
-  for (size_t i = 0; i < arraysize(types); i++) {
-    registrar_.Add(this,
-                   types[i],
-                   content::Source<Profile>(profile_));
+#if defined(OS_MACOSX)
+  if (!extension->is_platform_app()) {
+    error_ = keys::kCreateOnlyPackagedAppShortcutMac;
+    return false;
+  }
+#endif
+
+  Browser* browser = chrome::FindBrowserWithProfile(
+      GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
+  if (!browser) {
+    // Shouldn't happen if we have user gesture.
+    error_ = keys::kNoBrowserToCreateShortcut;
+    return false;
+  }
+
+  // Matched with a Release() in OnCloseShortcutPrompt().
+  AddRef();
+
+  if (auto_confirm_for_test == DO_NOT_SKIP) {
+    chrome::ShowCreateChromeAppShortcutsDialog(
+        browser->window()->GetNativeWindow(), browser->profile(), extension,
+        base::Bind(&ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt,
+           this));
+  } else {
+    OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
   }
+
+  // Response is sent async in OnCloseShortcutPrompt().
+  return true;
 }
 
-ManagementEventRouter::~ManagementEventRouter() {}
+bool ManagementSetLaunchTypeFunction::RunSync() {
+  if (!user_gesture()) {
+    error_ = keys::kGestureNeededForSetLaunchTypeError;
+    return false;
+  }
+
+  scoped_ptr<management::SetLaunchType::Params> params(
+      management::SetLaunchType::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+  const Extension* extension = service()->GetExtensionById(params->id, true);
+  if (!extension) {
+    error_ =
+        ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
+    return false;
+  }
+
+  if (!extension->is_app()) {
+    error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
+    return false;
+  }
+
+  std::vector<management::LaunchType> available_launch_types =
+      GetAvailableLaunchTypes(*extension);
 
-void ManagementEventRouter::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  const char* event_name = NULL;
-  const Extension* extension = NULL;
-  Profile* profile = content::Source<Profile>(source).ptr();
-  CHECK(profile);
-  CHECK(profile_->IsSameProfile(profile));
-
-  switch (type) {
-    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
-      event_name = management::OnInstalled::kEventName;
-      extension =
-          content::Details<const InstalledExtensionInfo>(details)->extension;
+  management::LaunchType app_launch_type = params->launch_type;
+  if (std::find(available_launch_types.begin(),
+                available_launch_types.end(),
+                app_launch_type) == available_launch_types.end()) {
+    error_ = keys::kLaunchTypeNotAvailableError;
+    return false;
+  }
+
+  LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
+  switch (app_launch_type) {
+    case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
+      launch_type = LAUNCH_TYPE_PINNED;
       break;
-    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
-      event_name = management::OnUninstalled::kEventName;
-      extension = content::Details<const Extension>(details).ptr();
+    case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
+      launch_type = LAUNCH_TYPE_REGULAR;
       break;
-    case chrome::NOTIFICATION_EXTENSION_LOADED:
-      event_name = management::OnEnabled::kEventName;
-      extension = content::Details<const Extension>(details).ptr();
+    case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
+      launch_type = LAUNCH_TYPE_FULLSCREEN;
       break;
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
-      event_name = management::OnDisabled::kEventName;
-      extension =
-          content::Details<const UnloadedExtensionInfo>(details)->extension;
+    case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
+      launch_type = LAUNCH_TYPE_WINDOW;
       break;
-    default:
+    case management::LAUNCH_TYPE_NONE:
       NOTREACHED();
-      return;
   }
-  DCHECK(event_name);
-  DCHECK(extension);
 
-  if (extension->ShouldNotBeVisible())
-    return; // Don't dispatch events for built-in extensions.
+  SetLaunchType(service(), params->id, launch_type);
+
+  return true;
+}
+
+ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {
+}
+
+ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {
+}
+
+void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp(
+    const Extension* extension,
+    const WebApplicationInfo& web_app_info) {
+  if (extension) {
+    scoped_ptr<management::ExtensionInfo> info =
+        CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
+    results_ = management::GenerateAppForLink::Results::Create(*info);
+
+    SendResponse(true);
+    Release();
+  } else {
+    error_ = keys::kGenerateAppForLinkInstallError;
+    SendResponse(false);
+    Release();
+  }
+}
+
+void ManagementGenerateAppForLinkFunction::OnFaviconForApp(
+    const favicon_base::FaviconImageResult& image_result) {
+  WebApplicationInfo web_app;
+  web_app.title = base::UTF8ToUTF16(title_);
+  web_app.app_url = launch_url_;
+
+  if (!image_result.image.IsEmpty()) {
+    WebApplicationInfo::IconInfo icon;
+    icon.data = image_result.image.AsBitmap();
+    icon.width = icon.data.width();
+    icon.height = icon.data.height();
+    web_app.icons.push_back(icon);
+  }
+
+  bookmark_app_helper_.reset(new BookmarkAppHelper(service(), web_app, NULL));
+  bookmark_app_helper_->Create(base::Bind(
+      &ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp, this));
+}
+
+bool ManagementGenerateAppForLinkFunction::RunAsync() {
+  if (!user_gesture()) {
+    error_ = keys::kGestureNeededForGenerateAppForLinkError;
+    return false;
+  }
+
+  scoped_ptr<management::GenerateAppForLink::Params> params(
+      management::GenerateAppForLink::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  GURL launch_url(params->url);
+  if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
+    error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidURLError,
+                                            params->url);
+    return false;
+  }
+
+  if (params->title.empty()) {
+    error_ = keys::kEmptyTitleError;
+    return false;
+  }
+
+  FaviconService* favicon_service =
+      FaviconServiceFactory::GetForProfile(GetProfile(),
+                                           Profile::EXPLICIT_ACCESS);
+  DCHECK(favicon_service);
+
+  title_ = params->title;
+  launch_url_ = launch_url;
+
+  favicon_service->GetFaviconImageForPageURL(
+      launch_url,
+      base::Bind(&ManagementGenerateAppForLinkFunction::OnFaviconForApp, this),
+      &cancelable_task_tracker_);
+
+  // Matched with a Release() in OnExtensionLoaded().
+  AddRef();
+
+  // Response is sent async in OnExtensionLoaded().
+  return true;
+}
+
+ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context)
+    : browser_context_(context), extension_registry_observer_(this) {
+  extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
+}
+
+ManagementEventRouter::~ManagementEventRouter() {}
+
+void ManagementEventRouter::OnExtensionLoaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension) {
+  BroadcastEvent(extension, management::OnEnabled::kEventName);
+}
+
+void ManagementEventRouter::OnExtensionUnloaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    UnloadedExtensionInfo::Reason reason) {
+  BroadcastEvent(extension, management::OnDisabled::kEventName);
+}
+
+void ManagementEventRouter::OnExtensionInstalled(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    bool is_update) {
+  BroadcastEvent(extension, management::OnInstalled::kEventName);
+}
+
+void ManagementEventRouter::OnExtensionUninstalled(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    extensions::UninstallReason reason) {
+  BroadcastEvent(extension, management::OnUninstalled::kEventName);
+}
 
+void ManagementEventRouter::BroadcastEvent(const Extension* extension,
+                                           const char* event_name) {
+  if (ui_util::ShouldNotBeVisible(extension, browser_context_))
+    return;  // Don't dispatch events for built-in extenions.
   scoped_ptr<base::ListValue> args(new base::ListValue());
   if (event_name == management::OnUninstalled::kEventName) {
     args->Append(new base::StringValue(extension->id()));
   } else {
-    scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
-        *extension, ExtensionSystem::Get(profile));
+    scoped_ptr<management::ExtensionInfo> info =
+        CreateExtensionInfo(*extension, ExtensionSystem::Get(browser_context_));
     args->Append(info->ToValue().release());
   }
 
-  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
-  ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
+  EventRouter::Get(browser_context_)
+      ->BroadcastEvent(scoped_ptr<Event>(new Event(event_name, args.Pass())));
 }
 
-ManagementAPI::ManagementAPI(Profile* profile)
-    : profile_(profile) {
-  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, management::OnInstalled::kEventName);
-  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, management::OnUninstalled::kEventName);
-  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, management::OnEnabled::kEventName);
-  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, management::OnDisabled::kEventName);
+ManagementAPI::ManagementAPI(content::BrowserContext* context)
+    : browser_context_(context) {
+  EventRouter* event_router = EventRouter::Get(browser_context_);
+  event_router->RegisterObserver(this, management::OnInstalled::kEventName);
+  event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
+  event_router->RegisterObserver(this, management::OnEnabled::kEventName);
+  event_router->RegisterObserver(this, management::OnDisabled::kEventName);
 }
 
 ManagementAPI::~ManagementAPI() {
 }
 
 void ManagementAPI::Shutdown() {
-  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
+  EventRouter::Get(browser_context_)->UnregisterObserver(this);
 }
 
-static base::LazyInstance<ProfileKeyedAPIFactory<ManagementAPI> >
-g_factory = LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI> >
+    g_factory = LAZY_INSTANCE_INITIALIZER;
 
 // static
-ProfileKeyedAPIFactory<ManagementAPI>* ManagementAPI::GetFactoryInstance() {
+BrowserContextKeyedAPIFactory<ManagementAPI>*
+ManagementAPI::GetFactoryInstance() {
   return g_factory.Pointer();
 }
 
 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
-  management_event_router_.reset(new ManagementEventRouter(profile_));
-  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
+  management_event_router_.reset(new ManagementEventRouter(browser_context_));
+  EventRouter::Get(browser_context_)->UnregisterObserver(this);
 }
 
 }  // namespace extensions