15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromecast/shell/browser/android/cast_window_android.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromecast/shell/browser/android/cast_window_manager.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/devtools_agent_host.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_controller.h"
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/public/browser/navigation_entry.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/renderer_preferences.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "jni/CastWindowAndroid_jni.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace chromecast {
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace shell {
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// The time (in milliseconds) we wait for after a page is closed (i.e.
238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// after an app is stopped) before we delete the corresponding WebContents.
248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const int kWebContentsDestructionDelayInMs = 50;
258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CastWindowAndroid::RegisterJni(JNIEnv* env) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return RegisterNativesImpl(env);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CastWindowAndroid::CastWindowAndroid(content::WebContents* web_contents)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : content::WebContentsObserver(web_contents),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      weak_factory_(this) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CastWindowAndroid::~CastWindowAndroid() {
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CastWindowAndroid* CastWindowAndroid::CreateNewWindow(
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserContext* browser_context,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& url) {
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::WebContents::CreateParams create_params(browser_context);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  create_params.routing_id = MSG_ROUTING_NONE;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WebContents* web_contents =
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::WebContents::Create(create_params);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CastWindowAndroid* shell = CreateCastWindowAndroid(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      create_params.initial_size);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url.is_empty())
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shell->LoadURL(url);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shell;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastWindowAndroid* CastWindowAndroid::CreateCastWindowAndroid(
598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    content::WebContents* web_contents,
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const gfx::Size& initial_size) {
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CastWindowAndroid* shell = new CastWindowAndroid(web_contents);
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  JNIEnv* env = base::android::AttachCurrentThread();
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::android::ScopedJavaLocalRef<jobject> shell_android(
658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      CreateCastWindowView(shell));
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  shell->java_object_.Reset(env, shell_android.Release());
688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  shell->web_contents_.reset(web_contents);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents->SetDelegate(shell);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Java_CastWindowAndroid_initFromNativeWebContents(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      env, shell->java_object_.obj(), reinterpret_cast<jint>(web_contents));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enabling hole-punching also requires runtime renderer preference
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents->GetMutableRendererPrefs()->
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_video_overlay_for_embedded_encrypted_video = true;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents->GetRenderViewHost()->SyncRendererPrefs();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shell;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CastWindowAndroid::Close() {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close page first, which fires the window.unload event. The WebContents
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // itself will be destroyed after browser-process has received renderer
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notification that the page is closed.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_contents_->GetRenderViewHost()->ClosePage();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CastWindowAndroid::Destroy() {
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: if multiple windows becomes supported, this may close other devtools
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // sessions.
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::DevToolsAgentHost::DetachAllClients();
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CloseCastWindowView(java_object_.obj());
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  delete this;
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CastWindowAndroid::LoadURL(const GURL& url) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NavigationController::LoadURLParams params(url);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.transition_type = ui::PageTransitionFromInt(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::PAGE_TRANSITION_TYPED |
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  web_contents_->GetController().LoadURLWithParams(params);
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  web_contents_->Focus();
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CastWindowAndroid::AddNewContents(content::WebContents* source,
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       content::WebContents* new_contents,
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       WindowOpenDisposition disposition,
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                       const gfx::Rect& initial_pos,
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       bool user_gesture,
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       bool* was_blocked) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (was_blocked) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *was_blocked = true;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CastWindowAndroid::CloseContents(content::WebContents* source) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(source, web_contents_.get());
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We need to delay the deletion of web_contents_ (currently for 50ms) to
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // give (and guarantee) the renderer enough time to finish 'onunload'
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // handler (but we don't want to wait any longer than that to delay the
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // starting of next app).
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // When shutting down in a test context, the last remaining WebContents
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // is torn down at browser-thread shutdown time. Call Destroy directly to
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // avoid losing the last posted task to delete this object.
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // TODO(gunsch): This could probably be avoided by using a
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // CompletionCallback in StopCurrentApp to wait until the app is completely
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // stopped. This might require a separate message loop and might only be
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // appropriate for test contexts or during shutdown, since it triggers a
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // wait on the main thread.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Destroy();
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MessageLoopProxy::current()->PostDelayedTask(
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CastWindowAndroid::Destroy, weak_factory_.GetWeakPtr()),
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CastWindowAndroid::CanOverscrollContent() const {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CastWindowAndroid::AddMessageToConsole(content::WebContents* source,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            int32 level,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const base::string16& message,
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            int32 line_no,
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const base::string16& source_id) {
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return false;
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CastWindowAndroid::ActivateContents(content::WebContents* contents) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(contents, web_contents_.get());
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents->GetRenderViewHost()->Focus();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CastWindowAndroid::DeactivateContents(content::WebContents* contents) {
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(contents, web_contents_.get());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents->GetRenderViewHost()->Blur();
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Render process gone: status=" << status;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Destroy();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace shell
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromecast
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)