Home | History | Annotate | Download | only in apps
      1 // Copyright 2014 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/apps/chrome_app_delegate.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/strings/stringprintf.h"
      9 #include "chrome/browser/app_mode/app_mode_utils.h"
     10 #include "chrome/browser/apps/scoped_keep_alive.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
     13 #include "chrome/browser/favicon/favicon_tab_helper.h"
     14 #include "chrome/browser/file_select_helper.h"
     15 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
     16 #include "chrome/browser/platform_util.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/shell_integration.h"
     19 #include "chrome/browser/ui/browser.h"
     20 #include "chrome/browser/ui/browser_dialogs.h"
     21 #include "chrome/browser/ui/browser_tabstrip.h"
     22 #include "chrome/browser/ui/browser_window.h"
     23 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
     24 #include "chrome/browser/ui/web_contents_sizer.h"
     25 #include "chrome/browser/ui/zoom/zoom_controller.h"
     26 #include "chrome/common/extensions/chrome_extension_messages.h"
     27 #include "content/public/browser/browser_context.h"
     28 #include "content/public/browser/notification_service.h"
     29 #include "content/public/browser/render_view_host.h"
     30 #include "content/public/browser/web_contents.h"
     31 #include "content/public/browser/web_contents_delegate.h"
     32 #include "extensions/common/constants.h"
     33 
     34 #if defined(USE_ASH)
     35 #include "ash/shelf/shelf_constants.h"
     36 #endif
     37 
     38 #if defined(ENABLE_PRINTING)
     39 #if defined(ENABLE_FULL_PRINTING)
     40 #include "chrome/browser/printing/print_preview_message_handler.h"
     41 #include "chrome/browser/printing/print_view_manager.h"
     42 #else
     43 #include "chrome/browser/printing/print_view_manager_basic.h"
     44 #endif  // defined(ENABLE_FULL_PRINTING)
     45 #endif  // defined(ENABLE_PRINTING)
     46 
     47 namespace {
     48 
     49 bool disable_external_open_for_testing_ = false;
     50 
     51 // Opens a URL with Chromium (not external browser) with the right profile.
     52 content::WebContents* OpenURLFromTabInternal(
     53     content::BrowserContext* context,
     54     const content::OpenURLParams& params) {
     55   // Force all links to open in a new tab, even if they were trying to open a
     56   // window.
     57   chrome::NavigateParams new_tab_params(
     58       static_cast<Browser*>(NULL), params.url, params.transition);
     59   if (params.disposition == NEW_BACKGROUND_TAB) {
     60     new_tab_params.disposition = NEW_BACKGROUND_TAB;
     61   } else {
     62     new_tab_params.disposition = NEW_FOREGROUND_TAB;
     63     new_tab_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
     64   }
     65 
     66   new_tab_params.initiating_profile = Profile::FromBrowserContext(context);
     67   chrome::Navigate(&new_tab_params);
     68 
     69   return new_tab_params.target_contents;
     70 }
     71 
     72 // Helper class that opens a URL based on if this browser instance is the
     73 // default system browser. If it is the default, open the URL directly instead
     74 // of asking the system to open it.
     75 class OpenURLFromTabBasedOnBrowserDefault
     76     : public ShellIntegration::DefaultWebClientObserver {
     77  public:
     78   OpenURLFromTabBasedOnBrowserDefault(scoped_ptr<content::WebContents> source,
     79                                       const content::OpenURLParams& params)
     80       : source_(source.Pass()), params_(params) {}
     81 
     82   // Opens a URL when called with the result of if this is the default system
     83   // browser or not.
     84   virtual void SetDefaultWebClientUIState(
     85       ShellIntegration::DefaultWebClientUIState state) OVERRIDE {
     86     Profile* profile =
     87         Profile::FromBrowserContext(source_->GetBrowserContext());
     88     DCHECK(profile);
     89     if (!profile)
     90       return;
     91     switch (state) {
     92       case ShellIntegration::STATE_PROCESSING:
     93         break;
     94       case ShellIntegration::STATE_IS_DEFAULT:
     95         OpenURLFromTabInternal(profile, params_);
     96         break;
     97       case ShellIntegration::STATE_NOT_DEFAULT:
     98       case ShellIntegration::STATE_UNKNOWN:
     99         platform_util::OpenExternal(profile, params_.url);
    100         break;
    101     }
    102   }
    103 
    104   virtual bool IsOwnedByWorker() OVERRIDE { return true; }
    105 
    106  private:
    107   scoped_ptr<content::WebContents> source_;
    108   const content::OpenURLParams params_;
    109 };
    110 
    111 }  // namespace
    112 
    113 class ChromeAppDelegate::NewWindowContentsDelegate
    114     : public content::WebContentsDelegate {
    115  public:
    116   NewWindowContentsDelegate() {}
    117   virtual ~NewWindowContentsDelegate() {}
    118 
    119   virtual content::WebContents* OpenURLFromTab(
    120       content::WebContents* source,
    121       const content::OpenURLParams& params) OVERRIDE;
    122 
    123  private:
    124   DISALLOW_COPY_AND_ASSIGN(NewWindowContentsDelegate);
    125 };
    126 
    127 content::WebContents*
    128 ChromeAppDelegate::NewWindowContentsDelegate::OpenURLFromTab(
    129     content::WebContents* source,
    130     const content::OpenURLParams& params) {
    131   if (source) {
    132     // This NewWindowContentsDelegate was given ownership of the incoming
    133     // WebContents by being assigned as its delegate within
    134     // ChromeAppDelegate::AddNewContents, but this is the first time
    135     // NewWindowContentsDelegate actually sees the WebContents.
    136     // Here it is captured for deletion.
    137     scoped_ptr<content::WebContents> owned_source(source);
    138     scoped_refptr<ShellIntegration::DefaultWebClientWorker>
    139         check_if_default_browser_worker =
    140             new ShellIntegration::DefaultBrowserWorker(
    141                 new OpenURLFromTabBasedOnBrowserDefault(owned_source.Pass(),
    142                                                         params));
    143     // Object lifetime notes: The OpenURLFromTabBasedOnBrowserDefault is owned
    144     // by check_if_default_browser_worker. StartCheckIsDefault() takes lifetime
    145     // ownership of check_if_default_browser_worker and will clean up after
    146     // the asynchronous tasks.
    147     check_if_default_browser_worker->StartCheckIsDefault();
    148   }
    149   return NULL;
    150 }
    151 
    152 ChromeAppDelegate::ChromeAppDelegate(scoped_ptr<ScopedKeepAlive> keep_alive)
    153     : keep_alive_(keep_alive.Pass()),
    154       new_window_contents_delegate_(new NewWindowContentsDelegate()) {
    155   registrar_.Add(this,
    156                  chrome::NOTIFICATION_APP_TERMINATING,
    157                  content::NotificationService::AllSources());
    158 }
    159 
    160 ChromeAppDelegate::~ChromeAppDelegate() {
    161   // Unregister now to prevent getting notified if |keep_alive_| is the last.
    162   terminating_callback_.Reset();
    163 }
    164 
    165 void ChromeAppDelegate::DisableExternalOpenForTesting() {
    166   disable_external_open_for_testing_ = true;
    167 }
    168 
    169 void ChromeAppDelegate::InitWebContents(content::WebContents* web_contents) {
    170   FaviconTabHelper::CreateForWebContents(web_contents);
    171 
    172 #if defined(ENABLE_PRINTING)
    173 #if defined(ENABLE_FULL_PRINTING)
    174   printing::PrintViewManager::CreateForWebContents(web_contents);
    175   printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
    176 #else
    177   printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
    178 #endif  // defined(ENABLE_FULL_PRINTING)
    179 #endif  // defined(ENABLE_PRINTING)
    180   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
    181       web_contents);
    182 
    183   // Kiosk app supports zooming.
    184   if (chrome::IsRunningInForcedAppMode())
    185     ZoomController::CreateForWebContents(web_contents);
    186 }
    187 
    188 void ChromeAppDelegate::ResizeWebContents(content::WebContents* web_contents,
    189                                           const gfx::Size& size) {
    190   ::ResizeWebContents(web_contents, size);
    191 }
    192 
    193 content::WebContents* ChromeAppDelegate::OpenURLFromTab(
    194     content::BrowserContext* context,
    195     content::WebContents* source,
    196     const content::OpenURLParams& params) {
    197   return OpenURLFromTabInternal(context, params);
    198 }
    199 
    200 void ChromeAppDelegate::AddNewContents(content::BrowserContext* context,
    201                                        content::WebContents* new_contents,
    202                                        WindowOpenDisposition disposition,
    203                                        const gfx::Rect& initial_pos,
    204                                        bool user_gesture,
    205                                        bool* was_blocked) {
    206   if (!disable_external_open_for_testing_) {
    207     // We don't really want to open a window for |new_contents|, but we need to
    208     // capture its intended navigation. Here we give ownership to the
    209     // NewWindowContentsDelegate, which will dispose of the contents once
    210     // a navigation is captured.
    211     new_contents->SetDelegate(new_window_contents_delegate_.get());
    212     return;
    213   }
    214   chrome::ScopedTabbedBrowserDisplayer displayer(
    215       Profile::FromBrowserContext(context), chrome::GetActiveDesktop());
    216   // Force all links to open in a new tab, even if they were trying to open a
    217   // new window.
    218   disposition =
    219       disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
    220   chrome::AddWebContents(displayer.browser(),
    221                          NULL,
    222                          new_contents,
    223                          disposition,
    224                          initial_pos,
    225                          user_gesture,
    226                          was_blocked);
    227 }
    228 
    229 content::ColorChooser* ChromeAppDelegate::ShowColorChooser(
    230     content::WebContents* web_contents,
    231     SkColor initial_color) {
    232   return chrome::ShowColorChooser(web_contents, initial_color);
    233 }
    234 
    235 void ChromeAppDelegate::RunFileChooser(
    236     content::WebContents* tab,
    237     const content::FileChooserParams& params) {
    238   FileSelectHelper::RunFileChooser(tab, params);
    239 }
    240 
    241 void ChromeAppDelegate::RequestMediaAccessPermission(
    242     content::WebContents* web_contents,
    243     const content::MediaStreamRequest& request,
    244     const content::MediaResponseCallback& callback,
    245     const extensions::Extension* extension) {
    246   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
    247       web_contents, request, callback, extension);
    248 }
    249 
    250 bool ChromeAppDelegate::CheckMediaAccessPermission(
    251     content::WebContents* web_contents,
    252     const GURL& security_origin,
    253     content::MediaStreamType type,
    254     const extensions::Extension* extension) {
    255   return MediaCaptureDevicesDispatcher::GetInstance()
    256       ->CheckMediaAccessPermission(
    257           web_contents, security_origin, type, extension);
    258 }
    259 
    260 int ChromeAppDelegate::PreferredIconSize() {
    261 #if defined(USE_ASH)
    262   return ash::kShelfSize;
    263 #else
    264   return extension_misc::EXTENSION_ICON_SMALL;
    265 #endif
    266 }
    267 
    268 void ChromeAppDelegate::SetWebContentsBlocked(
    269     content::WebContents* web_contents,
    270     bool blocked) {
    271   // RenderViewHost may be NULL during shutdown.
    272   content::RenderViewHost* host = web_contents->GetRenderViewHost();
    273   if (host) {
    274     host->Send(new ChromeViewMsg_SetVisuallyDeemphasized(host->GetRoutingID(),
    275                                                          blocked));
    276   }
    277 }
    278 
    279 bool ChromeAppDelegate::IsWebContentsVisible(
    280     content::WebContents* web_contents) {
    281   return platform_util::IsVisible(web_contents->GetNativeView());
    282 }
    283 
    284 void ChromeAppDelegate::SetTerminatingCallback(const base::Closure& callback) {
    285   terminating_callback_ = callback;
    286 }
    287 
    288 void ChromeAppDelegate::Observe(int type,
    289                                 const content::NotificationSource& source,
    290                                 const content::NotificationDetails& details) {
    291   switch (type) {
    292     case chrome::NOTIFICATION_APP_TERMINATING:
    293       if (!terminating_callback_.is_null())
    294         terminating_callback_.Run();
    295       break;
    296     default:
    297       NOTREACHED() << "Received unexpected notification";
    298   }
    299 }
    300