blob: 015f30da278d4bd9944422a7a6b69436bda6ddb0 [file] [log] [blame]
// 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/threading/thread_task_runner_handle.h"
#include "chromecast/base/version.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
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(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_, web_contents_->GetJavaWebContents(),
web_contents_->GetRenderProcessHost()->GetID(),
base::android::ConvertUTF8ToJavaString(env, PRODUCT_VERSION));
// Enabling hole-punching also requires runtime renderer preference
content::RendererPreferences* prefs =
web_contents_->GetMutableRendererPrefs();
prefs->use_video_overlay_for_embedded_encrypted_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();
}
base::android::ScopedJavaLocalRef<jobject>
CastWindowAndroid::GetContentVideoViewEmbedder() {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_CastWindowAndroid_getContentVideoViewEmbedder(env, window_java_);
}
void CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) {
LOG(ERROR) << "Render process gone: status=" << status;
Destroy();
}
} // namespace shell
} // namespace chromecast