1// Copyright (c) 2012 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 "content/browser/android/content_video_view.h"
6
7#include "base/command_line.h"
8#include "base/logging.h"
9#include "content/browser/media/android/browser_media_player_manager.h"
10#include "content/browser/power_save_blocker_impl.h"
11#include "content/common/android/surface_texture_peer.h"
12#include "content/public/common/content_switches.h"
13#include "jni/ContentVideoView_jni.h"
14
15using base::android::AttachCurrentThread;
16using base::android::CheckException;
17using base::android::ScopedJavaGlobalRef;
18
19namespace content {
20
21namespace {
22// There can only be one content video view at a time, this holds onto that
23// singleton instance.
24ContentVideoView* g_content_video_view = NULL;
25
26}  // namespace
27
28static jobject GetSingletonJavaContentVideoView(JNIEnv*env, jclass) {
29  if (g_content_video_view)
30    return g_content_video_view->GetJavaObject(env).Release();
31  else
32    return NULL;
33}
34
35bool ContentVideoView::RegisterContentVideoView(JNIEnv* env) {
36  return RegisterNativesImpl(env);
37}
38
39bool ContentVideoView::HasContentVideoView() {
40  return g_content_video_view;
41}
42
43ContentVideoView::ContentVideoView(
44    const ScopedJavaLocalRef<jobject>& context,
45    const ScopedJavaLocalRef<jobject>& client,
46    BrowserMediaPlayerManager* manager)
47    : manager_(manager) {
48  DCHECK(!g_content_video_view);
49  JNIEnv *env = AttachCurrentThread();
50  j_content_video_view_ = JavaObjectWeakGlobalRef(env,
51      Java_ContentVideoView_createContentVideoView(env, context.obj(),
52          reinterpret_cast<intptr_t>(this), client.obj()).obj());
53  g_content_video_view = this;
54  CreatePowerSaveBlocker();
55}
56
57ContentVideoView::~ContentVideoView() {
58  DCHECK(g_content_video_view);
59  DestroyContentVideoView(true);
60  g_content_video_view = NULL;
61}
62
63void ContentVideoView::OpenVideo() {
64  JNIEnv* env = AttachCurrentThread();
65  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
66  if (!content_video_view.is_null()) {
67    CreatePowerSaveBlocker();
68    Java_ContentVideoView_openVideo(env, content_video_view.obj());
69  }
70}
71
72void ContentVideoView::OnMediaPlayerError(int error_type) {
73  JNIEnv* env = AttachCurrentThread();
74  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
75  if (!content_video_view.is_null()) {
76    power_save_blocker_.reset();
77    Java_ContentVideoView_onMediaPlayerError(env, content_video_view.obj(),
78        error_type);
79  }
80}
81
82void ContentVideoView::OnVideoSizeChanged(int width, int height) {
83  JNIEnv* env = AttachCurrentThread();
84  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
85  if (!content_video_view.is_null()) {
86    Java_ContentVideoView_onVideoSizeChanged(env, content_video_view.obj(),
87        width, height);
88  }
89}
90
91void ContentVideoView::OnBufferingUpdate(int percent) {
92  JNIEnv* env = AttachCurrentThread();
93  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
94  if (!content_video_view.is_null()) {
95    Java_ContentVideoView_onBufferingUpdate(env, content_video_view.obj(),
96        percent);
97  }
98}
99
100void ContentVideoView::OnPlaybackComplete() {
101  JNIEnv* env = AttachCurrentThread();
102  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
103  if (!content_video_view.is_null()) {
104    power_save_blocker_.reset();
105    Java_ContentVideoView_onPlaybackComplete(env, content_video_view.obj());
106  }
107}
108
109void ContentVideoView::OnExitFullscreen() {
110  DestroyContentVideoView(false);
111}
112
113void ContentVideoView::UpdateMediaMetadata() {
114  JNIEnv* env = AttachCurrentThread();
115  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
116  if (!content_video_view.is_null())
117    UpdateMediaMetadata(env, content_video_view.obj());
118}
119
120int ContentVideoView::GetVideoWidth(JNIEnv*, jobject obj) const {
121  media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
122  return player ? player->GetVideoWidth() : 0;
123}
124
125int ContentVideoView::GetVideoHeight(JNIEnv*, jobject obj) const {
126  media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
127  return player ? player->GetVideoHeight() : 0;
128}
129
130int ContentVideoView::GetDurationInMilliSeconds(JNIEnv*, jobject obj) const {
131  media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
132  return player ? player->GetDuration().InMilliseconds() : -1;
133}
134
135int ContentVideoView::GetCurrentPosition(JNIEnv*, jobject obj) const {
136  media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
137  return player ? player->GetCurrentTime().InMilliseconds() : 0;
138}
139
140bool ContentVideoView::IsPlaying(JNIEnv*, jobject obj) {
141  media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
142  return player ? player->IsPlaying() : false;
143}
144
145void ContentVideoView::SeekTo(JNIEnv*, jobject obj, jint msec) {
146  manager_->FullscreenPlayerSeek(msec);
147}
148
149void ContentVideoView::Play(JNIEnv*, jobject obj) {
150  CreatePowerSaveBlocker();
151  manager_->FullscreenPlayerPlay();
152}
153
154void ContentVideoView::Pause(JNIEnv*, jobject obj) {
155  power_save_blocker_.reset();
156  manager_->FullscreenPlayerPause();
157}
158
159void ContentVideoView::ExitFullscreen(
160    JNIEnv*, jobject, jboolean release_media_player) {
161  power_save_blocker_.reset();
162  j_content_video_view_.reset();
163  manager_->ExitFullscreen(release_media_player);
164}
165
166void ContentVideoView::SetSurface(JNIEnv* env, jobject obj,
167                                  jobject surface) {
168  manager_->SetVideoSurface(
169      gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
170}
171
172void ContentVideoView::UpdateMediaMetadata(JNIEnv* env, jobject obj) {
173  media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
174  if (player && player->IsPlayerReady())
175    Java_ContentVideoView_onUpdateMediaMetadata(
176        env, obj, player->GetVideoWidth(), player->GetVideoHeight(),
177        player->GetDuration().InMilliseconds(), player->CanPause(),
178        player->CanSeekForward(), player->CanSeekBackward());
179}
180
181ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
182  return j_content_video_view_.get(env);
183}
184
185gfx::NativeView ContentVideoView::GetNativeView() {
186  JNIEnv* env = AttachCurrentThread();
187  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
188  if (content_video_view.is_null())
189    return NULL;
190
191  return reinterpret_cast<gfx::NativeView>(
192      Java_ContentVideoView_getNativeViewAndroid(env,
193                                                 content_video_view.obj()));
194
195}
196
197void ContentVideoView::CreatePowerSaveBlocker() {
198  if (power_save_blocker_) return;
199
200  power_save_blocker_ = PowerSaveBlocker::Create(
201      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
202      "Playing video").Pass();
203  static_cast<PowerSaveBlockerImpl*>(power_save_blocker_.get())->
204      InitDisplaySleepBlocker(GetNativeView());
205}
206
207void ContentVideoView::DestroyContentVideoView(bool native_view_destroyed) {
208  JNIEnv* env = AttachCurrentThread();
209  ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
210  if (!content_video_view.is_null()) {
211    j_content_video_view_.reset();
212    Java_ContentVideoView_destroyContentVideoView(env,
213        content_video_view.obj(), native_view_destroyed);
214    j_content_video_view_.reset();
215  }
216}
217}  // namespace content
218