Home | History | Annotate | Download | only in android
      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 "chromecast/shell/browser/android/cast_window_android.h"
      6 
      7 #include "base/message_loop/message_loop_proxy.h"
      8 #include "base/path_service.h"
      9 #include "chromecast/shell/browser/android/cast_window_manager.h"
     10 #include "content/public/browser/devtools_agent_host.h"
     11 #include "content/public/browser/navigation_controller.h"
     12 #include "content/public/browser/navigation_entry.h"
     13 #include "content/public/browser/render_view_host.h"
     14 #include "content/public/common/renderer_preferences.h"
     15 #include "jni/CastWindowAndroid_jni.h"
     16 
     17 namespace chromecast {
     18 namespace shell {
     19 
     20 namespace {
     21 
     22 // The time (in milliseconds) we wait for after a page is closed (i.e.
     23 // after an app is stopped) before we delete the corresponding WebContents.
     24 const int kWebContentsDestructionDelayInMs = 50;
     25 
     26 }  // namespace
     27 
     28 // static
     29 bool CastWindowAndroid::RegisterJni(JNIEnv* env) {
     30   return RegisterNativesImpl(env);
     31 }
     32 
     33 CastWindowAndroid::CastWindowAndroid(content::WebContents* web_contents)
     34     : content::WebContentsObserver(web_contents),
     35       weak_factory_(this) {
     36 }
     37 
     38 CastWindowAndroid::~CastWindowAndroid() {
     39 }
     40 
     41 // static
     42 CastWindowAndroid* CastWindowAndroid::CreateNewWindow(
     43     content::BrowserContext* browser_context,
     44     const GURL& url) {
     45   content::WebContents::CreateParams create_params(browser_context);
     46   create_params.routing_id = MSG_ROUTING_NONE;
     47   content::WebContents* web_contents =
     48       content::WebContents::Create(create_params);
     49   CastWindowAndroid* shell = CreateCastWindowAndroid(
     50       web_contents,
     51       create_params.initial_size);
     52   if (!url.is_empty())
     53     shell->LoadURL(url);
     54   return shell;
     55 }
     56 
     57 // static
     58 CastWindowAndroid* CastWindowAndroid::CreateCastWindowAndroid(
     59     content::WebContents* web_contents,
     60     const gfx::Size& initial_size) {
     61   CastWindowAndroid* shell = new CastWindowAndroid(web_contents);
     62 
     63   JNIEnv* env = base::android::AttachCurrentThread();
     64   base::android::ScopedJavaLocalRef<jobject> shell_android(
     65       CreateCastWindowView(shell));
     66 
     67   shell->java_object_.Reset(env, shell_android.Release());
     68   shell->web_contents_.reset(web_contents);
     69   web_contents->SetDelegate(shell);
     70 
     71   Java_CastWindowAndroid_initFromNativeWebContents(
     72       env, shell->java_object_.obj(), reinterpret_cast<jint>(web_contents));
     73 
     74   // Enabling hole-punching also requires runtime renderer preference
     75   web_contents->GetMutableRendererPrefs()->
     76       use_video_overlay_for_embedded_encrypted_video = true;
     77   web_contents->GetRenderViewHost()->SyncRendererPrefs();
     78 
     79   return shell;
     80 }
     81 
     82 void CastWindowAndroid::Close() {
     83   // Close page first, which fires the window.unload event. The WebContents
     84   // itself will be destroyed after browser-process has received renderer
     85   // notification that the page is closed.
     86   web_contents_->GetRenderViewHost()->ClosePage();
     87 }
     88 
     89 void CastWindowAndroid::Destroy() {
     90   // Note: if multiple windows becomes supported, this may close other devtools
     91   // sessions.
     92   content::DevToolsAgentHost::DetachAllClients();
     93   CloseCastWindowView(java_object_.obj());
     94   delete this;
     95 }
     96 
     97 void CastWindowAndroid::LoadURL(const GURL& url) {
     98   content::NavigationController::LoadURLParams params(url);
     99   params.transition_type = ui::PageTransitionFromInt(
    100       ui::PAGE_TRANSITION_TYPED |
    101       ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
    102   web_contents_->GetController().LoadURLWithParams(params);
    103   web_contents_->Focus();
    104 }
    105 
    106 void CastWindowAndroid::AddNewContents(content::WebContents* source,
    107                                        content::WebContents* new_contents,
    108                                        WindowOpenDisposition disposition,
    109                                        const gfx::Rect& initial_pos,
    110                                        bool user_gesture,
    111                                        bool* was_blocked) {
    112   NOTIMPLEMENTED();
    113   if (was_blocked) {
    114     *was_blocked = true;
    115   }
    116 }
    117 
    118 void CastWindowAndroid::CloseContents(content::WebContents* source) {
    119   DCHECK_EQ(source, web_contents_.get());
    120 
    121   // We need to delay the deletion of web_contents_ (currently for 50ms) to
    122   // give (and guarantee) the renderer enough time to finish 'onunload'
    123   // handler (but we don't want to wait any longer than that to delay the
    124   // starting of next app).
    125 
    126   if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
    127     // When shutting down in a test context, the last remaining WebContents
    128     // is torn down at browser-thread shutdown time. Call Destroy directly to
    129     // avoid losing the last posted task to delete this object.
    130     // TODO(gunsch): This could probably be avoided by using a
    131     // CompletionCallback in StopCurrentApp to wait until the app is completely
    132     // stopped. This might require a separate message loop and might only be
    133     // appropriate for test contexts or during shutdown, since it triggers a
    134     // wait on the main thread.
    135     Destroy();
    136     return;
    137   }
    138 
    139   base::MessageLoopProxy::current()->PostDelayedTask(
    140       FROM_HERE,
    141       base::Bind(&CastWindowAndroid::Destroy, weak_factory_.GetWeakPtr()),
    142       base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs));
    143 }
    144 
    145 bool CastWindowAndroid::CanOverscrollContent() const {
    146   return false;
    147 }
    148 
    149 bool CastWindowAndroid::AddMessageToConsole(content::WebContents* source,
    150                                             int32 level,
    151                                             const base::string16& message,
    152                                             int32 line_no,
    153                                             const base::string16& source_id) {
    154   return false;
    155 }
    156 
    157 void CastWindowAndroid::ActivateContents(content::WebContents* contents) {
    158   DCHECK_EQ(contents, web_contents_.get());
    159   contents->GetRenderViewHost()->Focus();
    160 }
    161 
    162 void CastWindowAndroid::DeactivateContents(content::WebContents* contents) {
    163   DCHECK_EQ(contents, web_contents_.get());
    164   contents->GetRenderViewHost()->Blur();
    165 }
    166 
    167 void CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) {
    168   LOG(ERROR) << "Render process gone: status=" << status;
    169   Destroy();
    170 }
    171 
    172 }  // namespace shell
    173 }  // namespace chromecast
    174