11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/shell/browser/android/cast_window_android.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/message_loop/message_loop_proxy.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/path_service.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/shell/browser/android/cast_window_manager.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/devtools_agent_host.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/navigation_controller.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/navigation_entry.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/render_view_host.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/common/renderer_preferences.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "jni/CastWindowAndroid_jni.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace chromecast {
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace shell {
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The time (in milliseconds) we wait for after a page is closed (i.e.
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// after an app is stopped) before we delete the corresponding WebContents.
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kWebContentsDestructionDelayInMs = 50;
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool CastWindowAndroid::RegisterJni(JNIEnv* env) {
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return RegisterNativesImpl(env);
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciCastWindowAndroid::CastWindowAndroid(content::WebContents* web_contents)
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : content::WebContentsObserver(web_contents),
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciCastWindowAndroid::~CastWindowAndroid() {
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciCastWindowAndroid* CastWindowAndroid::CreateNewWindow(
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::BrowserContext* browser_context,
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& url) {
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::WebContents::CreateParams create_params(browser_context);
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  create_params.routing_id = MSG_ROUTING_NONE;
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::WebContents* web_contents =
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::WebContents::Create(create_params);
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CastWindowAndroid* shell = CreateCastWindowAndroid(
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      web_contents,
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      create_params.initial_size);
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!url.is_empty())
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    shell->LoadURL(url);
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return shell;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciCastWindowAndroid* CastWindowAndroid::CreateCastWindowAndroid(
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::WebContents* web_contents,
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const gfx::Size& initial_size) {
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CastWindowAndroid* shell = new CastWindowAndroid(web_contents);
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  JNIEnv* env = base::android::AttachCurrentThread();
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::android::ScopedJavaLocalRef<jobject> shell_android(
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CreateCastWindowView(shell));
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  shell->java_object_.Reset(env, shell_android.Release());
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  shell->web_contents_.reset(web_contents);
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents->SetDelegate(shell);
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Java_CastWindowAndroid_initFromNativeWebContents(
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      env, shell->java_object_.obj(), reinterpret_cast<jint>(web_contents));
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Enabling hole-punching also requires runtime renderer preference
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents->GetMutableRendererPrefs()->
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      use_video_overlay_for_embedded_encrypted_video = true;
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents->GetRenderViewHost()->SyncRendererPrefs();
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return shell;
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::Close() {
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Close page first, which fires the window.unload event. The WebContents
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // itself will be destroyed after browser-process has received renderer
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // notification that the page is closed.
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents_->GetRenderViewHost()->ClosePage();
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::Destroy() {
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Note: if multiple windows becomes supported, this may close other devtools
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // sessions.
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::DevToolsAgentHost::DetachAllClients();
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CloseCastWindowView(java_object_.obj());
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  delete this;
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::LoadURL(const GURL& url) {
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::NavigationController::LoadURLParams params(url);
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  params.transition_type = ui::PageTransitionFromInt(
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PAGE_TRANSITION_TYPED |
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents_->GetController().LoadURLWithParams(params);
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents_->Focus();
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::AddNewContents(content::WebContents* source,
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       content::WebContents* new_contents,
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       WindowOpenDisposition disposition,
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       const gfx::Rect& initial_pos,
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       bool user_gesture,
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       bool* was_blocked) {
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  NOTIMPLEMENTED();
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (was_blocked) {
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *was_blocked = true;
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::CloseContents(content::WebContents* source) {
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(source, web_contents_.get());
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We need to delay the deletion of web_contents_ (currently for 50ms) to
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // give (and guarantee) the renderer enough time to finish 'onunload'
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // handler (but we don't want to wait any longer than that to delay the
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // starting of next app).
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // When shutting down in a test context, the last remaining WebContents
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // is torn down at browser-thread shutdown time. Call Destroy directly to
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // avoid losing the last posted task to delete this object.
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(gunsch): This could probably be avoided by using a
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // CompletionCallback in StopCurrentApp to wait until the app is completely
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // stopped. This might require a separate message loop and might only be
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // appropriate for test contexts or during shutdown, since it triggers a
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // wait on the main thread.
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Destroy();
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::MessageLoopProxy::current()->PostDelayedTask(
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&CastWindowAndroid::Destroy, weak_factory_.GetWeakPtr()),
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs));
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool CastWindowAndroid::CanOverscrollContent() const {
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return false;
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool CastWindowAndroid::AddMessageToConsole(content::WebContents* source,
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            int32 level,
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            const base::string16& message,
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            int32 line_no,
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            const base::string16& source_id) {
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return false;
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::ActivateContents(content::WebContents* contents) {
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(contents, web_contents_.get());
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  contents->GetRenderViewHost()->Focus();
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::DeactivateContents(content::WebContents* contents) {
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(contents, web_contents_.get());
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  contents->GetRenderViewHost()->Blur();
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOG(ERROR) << "Render process gone: status=" << status;
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Destroy();
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace shell
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace chromecast
174