1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/extensions/launch_util.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/values.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_sync_service.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/extension_util.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "extensions/common/extension.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(USE_ASH)
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shell.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace extensions {
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A preference set by the the NTP to persist the desired launch container type
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// used for apps.
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char kPrefLaunchType[] = "launchType";
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace launch_util {
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterIntegerPref(
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_names::kBookmarkAppCreationLaunchType,
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LAUNCH_TYPE_WINDOW,
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace launch_util
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)LaunchType GetLaunchType(const ExtensionPrefs* prefs,
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                         const Extension* extension) {
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  LaunchType result = LAUNCH_TYPE_DEFAULT;
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Launch hosted apps as windows by default for streamlined hosted apps.
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (util::IsStreamlinedHostedAppsEnabled() &&
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extension->id() != extension_misc::kChromeAppId) {
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    result = LAUNCH_TYPE_WINDOW;
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int value = GetLaunchTypePrefValue(prefs, extension->id());
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (value >= LAUNCH_TYPE_FIRST && value < NUM_LAUNCH_TYPES)
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    result = static_cast<LaunchType>(value);
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(OS_MACOSX)
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // App windows are not yet supported on mac.  Pref sync could make
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // the launch type LAUNCH_TYPE_WINDOW, even if there is no UI to set it
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // on mac.
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!extension->is_platform_app() && result == LAUNCH_TYPE_WINDOW)
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      result = LAUNCH_TYPE_REGULAR;
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return result;
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LaunchType GetLaunchTypePrefValue(const ExtensionPrefs* prefs,
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  const std::string& extension_id) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int value = LAUNCH_TYPE_INVALID;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return prefs->ReadPrefAsInteger(extension_id, kPrefLaunchType, &value)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ? static_cast<LaunchType>(value) : LAUNCH_TYPE_INVALID;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SetLaunchType(ExtensionService* service,
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                   const std::string& extension_id,
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                   LaunchType launch_type) {
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(launch_type >= LAUNCH_TYPE_FIRST && launch_type < NUM_LAUNCH_TYPES);
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ExtensionPrefs::Get(service->profile())->UpdateExtensionPref(
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extension_id,
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kPrefLaunchType,
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new base::FundamentalValue(static_cast<int>(launch_type)));
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sync the launch type.
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Extension* extension = service->GetInstalledExtension(extension_id);
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (extension) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ExtensionSyncService::Get(service->profile())->
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SyncExtensionChangeIfNeeded(*extension);
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)LaunchContainer GetLaunchContainer(const ExtensionPrefs* prefs,
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                   const Extension* extension) {
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  LaunchContainer manifest_launch_container =
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      AppLaunchInfo::GetLaunchContainer(extension);
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const LaunchContainer kInvalidLaunchContainer =
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      static_cast<LaunchContainer>(-1);
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  LaunchContainer result = kInvalidLaunchContainer;
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (manifest_launch_container == LAUNCH_CONTAINER_PANEL) {
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Apps with app.launch.container = 'panel' should always respect the
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // manifest setting.
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    result = manifest_launch_container;
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else if (manifest_launch_container == LAUNCH_CONTAINER_TAB) {
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Look for prefs that indicate the user's choice of launch container. The
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // app's menu on the NTP provides a UI to set this preference.
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    LaunchType prefs_launch_type = GetLaunchType(prefs, extension);
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (prefs_launch_type == LAUNCH_TYPE_WINDOW) {
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // If the pref is set to launch a window (or no pref is set, and
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // window opening is the default), make the container a window.
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      result = LAUNCH_CONTAINER_WINDOW;
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(USE_ASH)
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (prefs_launch_type == LAUNCH_TYPE_FULLSCREEN &&
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) {
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // LAUNCH_TYPE_FULLSCREEN launches in a maximized app window in ash.
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // For desktop chrome AURA on all platforms we should open the
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // application in full screen mode in the current tab, on the same
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // lines as non AURA chrome.
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      result = LAUNCH_CONTAINER_WINDOW;
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else {
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // All other launch types (tab, pinned, fullscreen) are
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // implemented as tabs in a window.
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      result = LAUNCH_CONTAINER_TAB;
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else {
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If a new value for app.launch.container is added, logic for it should be
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // added here. LAUNCH_CONTAINER_WINDOW is not present because there is no
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // way to set it in a manifest.
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    NOTREACHED() << manifest_launch_container;
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // All paths should set |result|.
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (result == kInvalidLaunchContainer) {
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DLOG(FATAL) << "Failed to set a launch container.";
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    result = LAUNCH_CONTAINER_TAB;
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return result;
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool HasPreferredLaunchContainer(const ExtensionPrefs* prefs,
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 const Extension* extension) {
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int value = -1;
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  LaunchContainer manifest_launch_container =
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      AppLaunchInfo::GetLaunchContainer(extension);
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return manifest_launch_container == LAUNCH_CONTAINER_TAB &&
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      prefs->ReadPrefAsInteger(extension->id(), kPrefLaunchType, &value);
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace extensions
158