OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/ui/extensions/application_launch.h" |
| 6 |
| 7 #include "base/metrics/field_trial.h" |
| 8 #include "base/metrics/histogram.h" |
| 9 #include "chrome/browser/extensions/api/app/app_api.h" |
| 10 #include "chrome/browser/extensions/default_apps_trial.h" |
| 11 #include "chrome/browser/extensions/extension_prefs.h" |
| 12 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/extensions/extension_tab_helper.h" |
| 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 16 #include "chrome/browser/ui/browser.h" |
| 17 #include "chrome/browser/ui/browser_finder.h" |
| 18 #include "chrome/browser/ui/browser_window.h" |
| 19 #include "chrome/browser/ui/panels/panel_manager.h" |
| 20 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 21 #include "chrome/browser/web_applications/web_app.h" |
| 22 #include "chrome/common/extensions/extension.h" |
| 23 #include "chrome/common/extensions/extension_constants.h" |
| 24 #include "chrome/common/url_constants.h" |
| 25 #include "content/public/browser/render_view_host.h" |
| 26 #include "content/public/browser/web_contents.h" |
| 27 #include "content/public/browser/web_contents_view.h" |
| 28 #include "content/public/common/renderer_preferences.h" |
| 29 |
| 30 #if defined(USE_ASH) |
| 31 #include "ash/ash_switches.h" |
| 32 #include "chrome/browser/ui/views/ash/panel_view_aura.h" |
| 33 #endif |
| 34 |
| 35 using content::WebContents; |
| 36 using extensions::Extension; |
| 37 |
| 38 namespace { |
| 39 |
| 40 // Get the launch URL for a given extension, with optional override/fallback. |
| 41 // |override_url|, if non-empty, will be preferred over the extension's |
| 42 // launch url. |
| 43 GURL UrlForExtension(const Extension* extension, |
| 44 const GURL& override_url) { |
| 45 if (!extension) |
| 46 return override_url; |
| 47 |
| 48 GURL url; |
| 49 if (!override_url.is_empty()) { |
| 50 DCHECK(extension->web_extent().MatchesURL(override_url)); |
| 51 url = override_url; |
| 52 } else { |
| 53 url = extension->GetFullLaunchURL(); |
| 54 } |
| 55 |
| 56 // For extensions lacking launch urls, determine a reasonable fallback. |
| 57 if (!url.is_valid()) { |
| 58 url = extension->options_url(); |
| 59 if (!url.is_valid()) |
| 60 url = GURL(chrome::kChromeUIExtensionsURL); |
| 61 } |
| 62 |
| 63 return url; |
| 64 } |
| 65 |
| 66 bool AllowPanels(const std::string& app_name) { |
| 67 return PanelManager::ShouldUsePanels( |
| 68 web_app::GetExtensionIdFromApplicationName(app_name)); |
| 69 } |
| 70 |
| 71 } // namespace |
| 72 |
| 73 namespace application_launch { |
| 74 |
| 75 WebContents* OpenApplication(Profile* profile, |
| 76 const Extension* extension, |
| 77 extension_misc::LaunchContainer container, |
| 78 const GURL& override_url, |
| 79 WindowOpenDisposition disposition) { |
| 80 WebContents* tab = NULL; |
| 81 ExtensionPrefs* prefs = profile->GetExtensionService()->extension_prefs(); |
| 82 prefs->SetActiveBit(extension->id(), true); |
| 83 |
| 84 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100); |
| 85 |
| 86 if (extension->is_platform_app()) { |
| 87 extensions::AppEventRouter::DispatchOnLaunchedEvent(profile, extension); |
| 88 return NULL; |
| 89 } |
| 90 |
| 91 switch (container) { |
| 92 case extension_misc::LAUNCH_NONE: { |
| 93 NOTREACHED(); |
| 94 break; |
| 95 } |
| 96 case extension_misc::LAUNCH_PANEL: |
| 97 #if defined(USE_ASH) |
| 98 if (extension && |
| 99 CommandLine::ForCurrentProcess()->HasSwitch( |
| 100 ash::switches::kAuraPanelManager)) { |
| 101 tab = OpenApplicationPanel(profile, extension, override_url); |
| 102 break; |
| 103 } |
| 104 // else fall through to LAUNCH_WINDOW |
| 105 #endif |
| 106 case extension_misc::LAUNCH_WINDOW: |
| 107 tab = OpenApplicationWindow(profile, extension, container, |
| 108 override_url, NULL); |
| 109 break; |
| 110 case extension_misc::LAUNCH_TAB: { |
| 111 tab = OpenApplicationTab(profile, extension, override_url, |
| 112 disposition); |
| 113 break; |
| 114 } |
| 115 default: |
| 116 NOTREACHED(); |
| 117 break; |
| 118 } |
| 119 return tab; |
| 120 } |
| 121 |
| 122 #if defined(USE_ASH) |
| 123 WebContents* OpenApplicationPanel( |
| 124 Profile* profile, |
| 125 const Extension* extension, |
| 126 const GURL& url_input) { |
| 127 GURL url = UrlForExtension(extension, url_input); |
| 128 std::string app_name = |
| 129 web_app::GenerateApplicationNameFromExtensionId(extension->id()); |
| 130 gfx::Rect panel_bounds; |
| 131 panel_bounds.set_width(extension->launch_width()); |
| 132 panel_bounds.set_height(extension->launch_height()); |
| 133 PanelViewAura* panel_view = new PanelViewAura(app_name); |
| 134 panel_view->Init(profile, url, panel_bounds); |
| 135 return panel_view->WebContents(); |
| 136 } |
| 137 #endif |
| 138 |
| 139 WebContents* OpenApplicationWindow( |
| 140 Profile* profile, |
| 141 const Extension* extension, |
| 142 extension_misc::LaunchContainer container, |
| 143 const GURL& url_input, |
| 144 Browser** app_browser) { |
| 145 DCHECK(!url_input.is_empty() || extension); |
| 146 GURL url = UrlForExtension(extension, url_input); |
| 147 |
| 148 std::string app_name; |
| 149 app_name = extension ? |
| 150 web_app::GenerateApplicationNameFromExtensionId(extension->id()) : |
| 151 web_app::GenerateApplicationNameFromURL(url); |
| 152 |
| 153 Browser::Type type = Browser::TYPE_POPUP; |
| 154 if (extension && |
| 155 container == extension_misc::LAUNCH_PANEL && |
| 156 AllowPanels(app_name)) { |
| 157 type = Browser::TYPE_PANEL; |
| 158 } |
| 159 |
| 160 gfx::Rect window_bounds; |
| 161 if (extension) { |
| 162 window_bounds.set_width(extension->launch_width()); |
| 163 window_bounds.set_height(extension->launch_height()); |
| 164 } |
| 165 |
| 166 Browser::CreateParams params(type, profile); |
| 167 params.app_name = app_name; |
| 168 params.initial_bounds = window_bounds; |
| 169 |
| 170 #if defined(USE_ASH) |
| 171 if (extension && |
| 172 container == extension_misc::LAUNCH_WINDOW) { |
| 173 // In ash, LAUNCH_FULLSCREEN launches in a maximized app window and |
| 174 // LAUNCH_WINDOW launches in a normal app window. |
| 175 ExtensionPrefs::LaunchType launch_type = |
| 176 profile->GetExtensionService()->extension_prefs()->GetLaunchType( |
| 177 extension->id(), ExtensionPrefs::LAUNCH_DEFAULT); |
| 178 if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN) |
| 179 params.initial_show_state = ui::SHOW_STATE_MAXIMIZED; |
| 180 else if (launch_type == ExtensionPrefs::LAUNCH_WINDOW) |
| 181 params.initial_show_state = ui::SHOW_STATE_NORMAL; |
| 182 } |
| 183 #endif |
| 184 |
| 185 Browser* browser = Browser::CreateWithParams(params); |
| 186 |
| 187 if (app_browser) |
| 188 *app_browser = browser; |
| 189 |
| 190 TabContentsWrapper* wrapper = |
| 191 browser->AddSelectedTabWithURL(url, content::PAGE_TRANSITION_START_PAGE); |
| 192 WebContents* contents = wrapper->web_contents(); |
| 193 contents->GetMutableRendererPrefs()->can_accept_load_drops = false; |
| 194 contents->GetRenderViewHost()->SyncRendererPrefs(); |
| 195 // TODO(stevenjb): Find the right centralized place to do this. Currently it |
| 196 // is only done for app tabs in normal browsers through SetExtensionAppById. |
| 197 if (extension && type == Browser::TYPE_PANEL) |
| 198 wrapper->extension_tab_helper()->SetExtensionAppIconById(extension->id()); |
| 199 |
| 200 browser->window()->Show(); |
| 201 |
| 202 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial |
| 203 // focus explicitly. |
| 204 contents->GetView()->SetInitialFocus(); |
| 205 return contents; |
| 206 } |
| 207 |
| 208 WebContents* OpenAppShortcutWindow(Profile* profile, |
| 209 const GURL& url, |
| 210 bool update_shortcut) { |
| 211 Browser* app_browser; |
| 212 WebContents* tab = OpenApplicationWindow( |
| 213 profile, |
| 214 NULL, // this is a URL app. No extension. |
| 215 extension_misc::LAUNCH_WINDOW, |
| 216 url, |
| 217 &app_browser); |
| 218 |
| 219 if (!tab) |
| 220 return NULL; |
| 221 |
| 222 if (update_shortcut) { |
| 223 // Set UPDATE_SHORTCUT as the pending web app action. This action is picked |
| 224 // up in LoadingStateChanged to schedule a GetApplicationInfo. And when |
| 225 // the web app info is available, ExtensionTabHelper notifies Browser via |
| 226 // OnDidGetApplicationInfo, which calls |
| 227 // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as |
| 228 // pending web app action. |
| 229 app_browser->set_pending_web_app_action(Browser::UPDATE_SHORTCUT); |
| 230 } |
| 231 return tab; |
| 232 } |
| 233 |
| 234 WebContents* OpenApplicationTab(Profile* profile, |
| 235 const Extension* extension, |
| 236 const GURL& override_url, |
| 237 WindowOpenDisposition disposition) { |
| 238 Browser* browser = browser::FindTabbedBrowser(profile, false); |
| 239 WebContents* contents = NULL; |
| 240 if (!browser) { |
| 241 // No browser for this profile, need to open a new one. |
| 242 browser = Browser::Create(profile); |
| 243 browser->window()->Show(); |
| 244 // There's no current tab in this browser window, so add a new one. |
| 245 disposition = NEW_FOREGROUND_TAB; |
| 246 } else { |
| 247 // For existing browser, ensure its window is activated. |
| 248 browser->window()->Activate(); |
| 249 } |
| 250 |
| 251 // Check the prefs for overridden mode. |
| 252 ExtensionService* extension_service = profile->GetExtensionService(); |
| 253 DCHECK(extension_service); |
| 254 |
| 255 ExtensionPrefs::LaunchType launch_type = |
| 256 extension_service->extension_prefs()->GetLaunchType( |
| 257 extension->id(), ExtensionPrefs::LAUNCH_DEFAULT); |
| 258 UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100); |
| 259 |
| 260 static bool default_apps_trial_exists = |
| 261 base::FieldTrialList::TrialExists(kDefaultAppsTrialName); |
| 262 if (default_apps_trial_exists) { |
| 263 UMA_HISTOGRAM_ENUMERATION( |
| 264 base::FieldTrial::MakeName("Extensions.AppTabLaunchType", |
| 265 kDefaultAppsTrialName), |
| 266 launch_type, 100); |
| 267 } |
| 268 |
| 269 int add_type = TabStripModel::ADD_ACTIVE; |
| 270 if (launch_type == ExtensionPrefs::LAUNCH_PINNED) |
| 271 add_type |= TabStripModel::ADD_PINNED; |
| 272 |
| 273 GURL extension_url = UrlForExtension(extension, override_url); |
| 274 // TODO(erikkay): START_PAGE doesn't seem like the right transition in all |
| 275 // cases. |
| 276 browser::NavigateParams params(browser, extension_url, |
| 277 content::PAGE_TRANSITION_START_PAGE); |
| 278 params.tabstrip_add_types = add_type; |
| 279 params.disposition = disposition; |
| 280 |
| 281 if (disposition == CURRENT_TAB) { |
| 282 WebContents* existing_tab = browser->GetSelectedWebContents(); |
| 283 TabStripModel* model = browser->tab_strip_model(); |
| 284 int tab_index = model->GetWrapperIndex(existing_tab); |
| 285 |
| 286 existing_tab->OpenURL(content::OpenURLParams( |
| 287 extension_url, |
| 288 content::Referrer(existing_tab->GetURL(), |
| 289 WebKit::WebReferrerPolicyDefault), |
| 290 disposition, content::PAGE_TRANSITION_LINK, false)); |
| 291 // Reset existing_tab as OpenURL() may have clobbered it. |
| 292 existing_tab = browser->GetSelectedWebContents(); |
| 293 if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) { |
| 294 model->SetTabPinned(tab_index, true); |
| 295 // Pinning may have moved the tab. |
| 296 tab_index = model->GetWrapperIndex(existing_tab); |
| 297 } |
| 298 if (params.tabstrip_add_types & TabStripModel::ADD_ACTIVE) |
| 299 model->ActivateTabAt(tab_index, true); |
| 300 |
| 301 contents = existing_tab; |
| 302 } else { |
| 303 browser::Navigate(¶ms); |
| 304 contents = params.target_contents->web_contents(); |
| 305 } |
| 306 |
| 307 #if defined(USE_ASH) |
| 308 // In ash, LAUNCH_FULLSCREEN launches in a maximized app window and it should |
| 309 // not reach here. |
| 310 DCHECK(launch_type != ExtensionPrefs::LAUNCH_FULLSCREEN); |
| 311 #else |
| 312 // TODO(skerner): If we are already in full screen mode, and the user |
| 313 // set the app to open as a regular or pinned tab, what should happen? |
| 314 // Today we open the tab, but stay in full screen mode. Should we leave |
| 315 // full screen mode in this case? |
| 316 if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN && |
| 317 !browser->window()->IsFullscreen()) { |
| 318 browser->ToggleFullscreenMode(); |
| 319 } |
| 320 #endif |
| 321 |
| 322 return contents; |
| 323 } |
| 324 |
| 325 } // namespace application_launch |
OLD | NEW |