// Copyright 2014 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 "chromecast/browser/android/cast_window_android.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" #include "chromecast/browser/android/cast_window_manager.h" #include "chromecast/browser/cast_content_window.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/renderer_preferences.h" #include "jni/CastWindowAndroid_jni.h" #include "ui/gfx/skia_util.h" namespace chromecast { namespace shell { namespace { // The time (in milliseconds) we wait for after a page is closed (i.e. // after an app is stopped) before we delete the corresponding WebContents. const int kWebContentsDestructionDelayInMs = 50; } // namespace // static bool CastWindowAndroid::RegisterJni(JNIEnv* env) { return RegisterNativesImpl(env); } // static CastWindowAndroid* CastWindowAndroid::CreateNewWindow( content::BrowserContext* browser_context, const GURL& url) { CastWindowAndroid* window_android = new CastWindowAndroid(browser_context); window_android->Initialize(); if (!url.is_empty()) window_android->LoadURL(url); content::RenderWidgetHostView* rwhv = window_android->web_contents_->GetRenderWidgetHostView(); if (rwhv) { rwhv->SetBackgroundColor(SK_ColorBLACK); } return window_android; } CastWindowAndroid::CastWindowAndroid(content::BrowserContext* browser_context) : browser_context_(browser_context), content_window_(new CastContentWindow), weak_factory_(this) { } void CastWindowAndroid::Initialize() { web_contents_ = content_window_->CreateWebContents(gfx::Size(), browser_context_); web_contents_->SetDelegate(this); content::WebContentsObserver::Observe(web_contents_.get()); JNIEnv* env = base::android::AttachCurrentThread(); window_java_.Reset(CreateCastWindowView(this)); Java_CastWindowAndroid_initFromNativeWebContents( env, window_java_.obj(), web_contents_->GetJavaWebContents().obj(), web_contents_->GetRenderProcessHost()->GetID()); // Enabling hole-punching also requires runtime renderer preference content::RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs(); prefs->use_video_overlay_for_embedded_encrypted_video = true; prefs->use_view_overlay_for_all_video = true; web_contents_->GetRenderViewHost()->SyncRendererPrefs(); } CastWindowAndroid::~CastWindowAndroid() { } void CastWindowAndroid::Close() { // Close page first, which fires the window.unload event. The WebContents // itself will be destroyed after browser-process has received renderer // notification that the page is closed. web_contents_->ClosePage(); } void CastWindowAndroid::Destroy() { // Note: if multiple windows becomes supported, this may close other devtools // sessions. content::DevToolsAgentHost::DetachAllClients(); CloseCastWindowView(window_java_.obj()); delete this; } void CastWindowAndroid::LoadURL(const GURL& url) { content::NavigationController::LoadURLParams params(url); params.transition_type = ui::PageTransitionFromInt( ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); web_contents_->GetController().LoadURLWithParams(params); web_contents_->Focus(); } void CastWindowAndroid::AddNewContents(content::WebContents* source, content::WebContents* new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, bool* was_blocked) { NOTIMPLEMENTED(); if (was_blocked) { *was_blocked = true; } } void CastWindowAndroid::CloseContents(content::WebContents* source) { DCHECK_EQ(source, web_contents_.get()); // We need to delay the deletion of web_contents_ (currently for 50ms) to // give (and guarantee) the renderer enough time to finish 'onunload' // handler (but we don't want to wait any longer than that to delay the // starting of next app). base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&CastWindowAndroid::Destroy, weak_factory_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs)); } bool CastWindowAndroid::CanOverscrollContent() const { return false; } bool CastWindowAndroid::AddMessageToConsole(content::WebContents* source, int32_t level, const base::string16& message, int32_t line_no, const base::string16& source_id) { return false; } void CastWindowAndroid::ActivateContents(content::WebContents* contents) { DCHECK_EQ(contents, web_contents_.get()); contents->GetRenderViewHost()->GetWidget()->Focus(); } void CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) { LOG(ERROR) << "Render process gone: status=" << status; Destroy(); } } // namespace shell } // namespace chromecast