text: // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/extensions/launch_util.h"
  
  #include "base/values.h"
  #include "chrome/browser/extensions/extension_service.h"
  #include "chrome/browser/extensions/extension_sync_service.h"
  #include "chrome/browser/profiles/profile.h"
  #include "chrome/browser/ui/host_desktop.h"
  #include "chrome/common/extensions/extension_constants.h"
  #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
  #include "components/pref_registry/pref_registry_syncable.h"
  #include "extensions/browser/extension_prefs.h"
  #include "extensions/browser/pref_names.h"
  #include "extensions/common/extension.h"
  
  #if defined(USE_ASH)
  #include "ash/shell.h"
  #endif
  
  namespace extensions {
  namespace {
  
  // A preference set by the the NTP to persist the desired launch container type
  // used for apps.
  const char kPrefLaunchType[] = "launchType";
  
  }  // namespace
  
  namespace launch_util {
  
  // static
  void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
    registry->RegisterIntegerPref(
        pref_names::kBookmarkAppCreationLaunchType,
        LAUNCH_TYPE_WINDOW,
        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  }
  
  }  // namespace launch_util
  
  LaunchType GetLaunchType(const ExtensionPrefs* prefs,
                           const Extension* extension) {
    LaunchType result = LAUNCH_TYPE_DEFAULT;
  
    int value = GetLaunchTypePrefValue(prefs, extension->id());
    if (value >= LAUNCH_TYPE_FIRST && value < NUM_LAUNCH_TYPES)
      result = static_cast<LaunchType>(value);
  
    return result;
  }
  
  LaunchType GetLaunchTypePrefValue(const ExtensionPrefs* prefs,
                                    const std::string& extension_id) {
    int value = LAUNCH_TYPE_INVALID;
    return prefs->ReadPrefAsInteger(extension_id, kPrefLaunchType, &value)
        ? static_cast<LaunchType>(value) : LAUNCH_TYPE_INVALID;
  }
  
  void SetLaunchType(ExtensionService* service,
                     const std::string& extension_id,
                     LaunchType launch_type) {
    DCHECK(launch_type >= LAUNCH_TYPE_FIRST && launch_type < NUM_LAUNCH_TYPES);
  
    ExtensionPrefs::Get(service->profile())->UpdateExtensionPref(
        extension_id,
        kPrefLaunchType,
        new base::FundamentalValue(static_cast<int>(launch_type)));
  
    // Sync the launch type.
    const Extension* extension = service->GetInstalledExtension(extension_id);
    if (extension) {
      ExtensionSyncService::Get(service->profile())->
          SyncExtensionChangeIfNeeded(*extension);
    }
  }
  
  LaunchContainer GetLaunchContainer(const ExtensionPrefs* prefs,
                                     const Extension* extension) {
    LaunchContainer manifest_launch_container =
        AppLaunchInfo::GetLaunchContainer(extension);
  
    const LaunchContainer kInvalidLaunchContainer =
        static_cast<LaunchContainer>(-1);
  
    LaunchContainer result = kInvalidLaunchContainer;
  
    if (manifest_launch_container == LAUNCH_CONTAINER_PANEL) {
      // Apps with app.launch.container = 'panel' should always respect the
      // manifest setting.
      result = manifest_launch_container;
    } else if (manifest_launch_container == LAUNCH_CONTAINER_TAB) {
      // Look for prefs that indicate the user's choice of launch container. The
      // app's menu on the NTP provides a UI to set this preference.
      LaunchType prefs_launch_type = GetLaunchType(prefs, extension);
  
      if (prefs_launch_type == LAUNCH_TYPE_WINDOW) {
        // If the pref is set to launch a window (or no pref is set, and
        // window opening is the default), make the container a window.
        result = LAUNCH_CONTAINER_WINDOW;
  #if defined(USE_ASH)
      } else if (prefs_launch_type == LAUNCH_TYPE_FULLSCREEN &&
                 chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) {
        // LAUNCH_TYPE_FULLSCREEN launches in a maximized app window in ash.
        // For desktop chrome AURA on all platforms we should open the
        // application in full screen mode in the current tab, on the same
        // lines as non AURA chrome.
        result = LAUNCH_CONTAINER_WINDOW;
  #endif
      } else {
        // All other launch types (tab, pinned, fullscreen) are
        // implemented as tabs in a window.
        result = LAUNCH_CONTAINER_TAB;
      }
    } else {
      // If a new value for app.launch.container is added, logic for it should be
      // added here. LAUNCH_CONTAINER_WINDOW is not present because there is no
      // way to set it in a manifest.
      NOTREACHED() << manifest_launch_container;
    }
  
    // All paths should set |result|.
    if (result == kInvalidLaunchContainer) {
      DLOG(FATAL) << "Failed to set a launch container.";
      result = LAUNCH_CONTAINER_TAB;
    }
  
    return result;
  }
  
  bool HasPreferredLaunchContainer(const ExtensionPrefs* prefs,
                                   const Extension* extension) {
    int value = -1;
    LaunchContainer manifest_launch_container =
        AppLaunchInfo::GetLaunchContainer(extension);
    return manifest_launch_container == LAUNCH_CONTAINER_TAB &&
        prefs->ReadPrefAsInteger(extension->id(), kPrefLaunchType, &value);
  }
  
  }  // namespace extensions
  