• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "content/browser/android/content_view_core_impl.h"
12 #include "content/browser/media/android/browser_media_player_manager.h"
13 #include "content/browser/power_save_blocker_impl.h"
14 #include "content/common/android/surface_texture_peer.h"
15 #include "content/public/browser/user_metrics.h"
16 #include "content/public/common/content_switches.h"
17 #include "jni/ContentVideoView_jni.h"
18 
19 using base::android::AttachCurrentThread;
20 using base::android::CheckException;
21 using base::android::ScopedJavaGlobalRef;
22 using base::UserMetricsAction;
23 using content::RecordAction;
24 
25 namespace content {
26 
27 namespace {
28 // There can only be one content video view at a time, this holds onto that
29 // singleton instance.
30 ContentVideoView* g_content_video_view = NULL;
31 
32 }  // namespace
33 
GetSingletonJavaContentVideoView(JNIEnv * env,jclass)34 static jobject GetSingletonJavaContentVideoView(JNIEnv*env, jclass) {
35   if (g_content_video_view)
36     return g_content_video_view->GetJavaObject(env).Release();
37   else
38     return NULL;
39 }
40 
RegisterContentVideoView(JNIEnv * env)41 bool ContentVideoView::RegisterContentVideoView(JNIEnv* env) {
42   return RegisterNativesImpl(env);
43 }
44 
GetInstance()45 ContentVideoView* ContentVideoView::GetInstance() {
46   return g_content_video_view;
47 }
48 
ContentVideoView(BrowserMediaPlayerManager * manager)49 ContentVideoView::ContentVideoView(
50     BrowserMediaPlayerManager* manager)
51     : manager_(manager),
52       weak_factory_(this) {
53   DCHECK(!g_content_video_view);
54   j_content_video_view_ = CreateJavaObject();
55   g_content_video_view = this;
56   CreatePowerSaveBlocker();
57 }
58 
~ContentVideoView()59 ContentVideoView::~ContentVideoView() {
60   DCHECK(g_content_video_view);
61   JNIEnv* env = AttachCurrentThread();
62   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
63   if (!content_video_view.is_null()) {
64     Java_ContentVideoView_destroyContentVideoView(env,
65         content_video_view.obj(), true);
66     j_content_video_view_.reset();
67   }
68   g_content_video_view = NULL;
69 }
70 
OpenVideo()71 void ContentVideoView::OpenVideo() {
72   JNIEnv* env = AttachCurrentThread();
73   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
74   if (!content_video_view.is_null()) {
75     CreatePowerSaveBlocker();
76     Java_ContentVideoView_openVideo(env, content_video_view.obj());
77   }
78 }
79 
OnMediaPlayerError(int error_type)80 void ContentVideoView::OnMediaPlayerError(int error_type) {
81   JNIEnv* env = AttachCurrentThread();
82   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
83   if (!content_video_view.is_null()) {
84     power_save_blocker_.reset();
85     Java_ContentVideoView_onMediaPlayerError(env, content_video_view.obj(),
86         error_type);
87   }
88 }
89 
OnVideoSizeChanged(int width,int height)90 void ContentVideoView::OnVideoSizeChanged(int width, int height) {
91   JNIEnv* env = AttachCurrentThread();
92   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
93   if (!content_video_view.is_null()) {
94     Java_ContentVideoView_onVideoSizeChanged(env, content_video_view.obj(),
95         width, height);
96   }
97 }
98 
OnBufferingUpdate(int percent)99 void ContentVideoView::OnBufferingUpdate(int percent) {
100   JNIEnv* env = AttachCurrentThread();
101   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
102   if (!content_video_view.is_null()) {
103     Java_ContentVideoView_onBufferingUpdate(env, content_video_view.obj(),
104         percent);
105   }
106 }
107 
OnPlaybackComplete()108 void ContentVideoView::OnPlaybackComplete() {
109   JNIEnv* env = AttachCurrentThread();
110   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
111   if (!content_video_view.is_null()) {
112     power_save_blocker_.reset();
113     Java_ContentVideoView_onPlaybackComplete(env, content_video_view.obj());
114   }
115 }
116 
OnExitFullscreen()117 void ContentVideoView::OnExitFullscreen() {
118   JNIEnv* env = AttachCurrentThread();
119   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
120   if (!content_video_view.is_null())
121     Java_ContentVideoView_onExitFullscreen(env, content_video_view.obj());
122 }
123 
RecordFullscreenPlayback(JNIEnv *,jobject,bool is_portrait_video,bool is_orientation_portrait)124 void ContentVideoView::RecordFullscreenPlayback(
125     JNIEnv*, jobject, bool is_portrait_video, bool is_orientation_portrait) {
126   UMA_HISTOGRAM_BOOLEAN("MobileFullscreenVideo.OrientationPortrait",
127                         is_orientation_portrait);
128   UMA_HISTOGRAM_BOOLEAN("MobileFullscreenVideo.VideoPortrait",
129                         is_portrait_video);
130 }
131 
RecordExitFullscreenPlayback(JNIEnv *,jobject,bool is_portrait_video,long playback_duration_in_milliseconds_before_orientation_change,long playback_duration_in_milliseconds_after_orientation_change)132 void ContentVideoView::RecordExitFullscreenPlayback(
133     JNIEnv*, jobject, bool is_portrait_video,
134     long playback_duration_in_milliseconds_before_orientation_change,
135     long playback_duration_in_milliseconds_after_orientation_change) {
136   bool orientation_changed = (
137       playback_duration_in_milliseconds_after_orientation_change != 0);
138   if (is_portrait_video) {
139     UMA_HISTOGRAM_COUNTS(
140         "MobileFullscreenVideo.PortraitDuration",
141         playback_duration_in_milliseconds_before_orientation_change);
142     UMA_HISTOGRAM_COUNTS(
143         "MobileFullscreenVideo.PortraitRotation", orientation_changed);
144     if (orientation_changed) {
145       UMA_HISTOGRAM_COUNTS(
146           "MobileFullscreenVideo.DurationAfterPotraitRotation",
147           playback_duration_in_milliseconds_after_orientation_change);
148     }
149   } else {
150     UMA_HISTOGRAM_COUNTS(
151         "MobileFullscreenVideo.LandscapeDuration",
152         playback_duration_in_milliseconds_before_orientation_change);
153     UMA_HISTOGRAM_COUNTS(
154         "MobileFullscreenVideo.LandscapeRotation", orientation_changed);
155   }
156 }
157 
UpdateMediaMetadata()158 void ContentVideoView::UpdateMediaMetadata() {
159   JNIEnv* env = AttachCurrentThread();
160   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
161   if (content_video_view.is_null())
162     return;
163 
164   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
165   if (player && player->IsPlayerReady()) {
166     Java_ContentVideoView_onUpdateMediaMetadata(
167         env, content_video_view.obj(), player->GetVideoWidth(),
168         player->GetVideoHeight(),
169         static_cast<int>(player->GetDuration().InMilliseconds()),
170         player->CanPause(),player->CanSeekForward(), player->CanSeekBackward());
171   }
172 }
173 
GetVideoWidth(JNIEnv *,jobject obj) const174 int ContentVideoView::GetVideoWidth(JNIEnv*, jobject obj) const {
175   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
176   return player ? player->GetVideoWidth() : 0;
177 }
178 
GetVideoHeight(JNIEnv *,jobject obj) const179 int ContentVideoView::GetVideoHeight(JNIEnv*, jobject obj) const {
180   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
181   return player ? player->GetVideoHeight() : 0;
182 }
183 
GetDurationInMilliSeconds(JNIEnv *,jobject obj) const184 int ContentVideoView::GetDurationInMilliSeconds(JNIEnv*, jobject obj) const {
185   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
186   return player ? player->GetDuration().InMilliseconds() : -1;
187 }
188 
GetCurrentPosition(JNIEnv *,jobject obj) const189 int ContentVideoView::GetCurrentPosition(JNIEnv*, jobject obj) const {
190   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
191   return player ? player->GetCurrentTime().InMilliseconds() : 0;
192 }
193 
IsPlaying(JNIEnv *,jobject obj)194 bool ContentVideoView::IsPlaying(JNIEnv*, jobject obj) {
195   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
196   return player ? player->IsPlaying() : false;
197 }
198 
SeekTo(JNIEnv *,jobject obj,jint msec)199 void ContentVideoView::SeekTo(JNIEnv*, jobject obj, jint msec) {
200   manager_->FullscreenPlayerSeek(msec);
201 }
202 
Play(JNIEnv *,jobject obj)203 void ContentVideoView::Play(JNIEnv*, jobject obj) {
204   CreatePowerSaveBlocker();
205   manager_->FullscreenPlayerPlay();
206 }
207 
Pause(JNIEnv *,jobject obj)208 void ContentVideoView::Pause(JNIEnv*, jobject obj) {
209   power_save_blocker_.reset();
210   manager_->FullscreenPlayerPause();
211 }
212 
ExitFullscreen(JNIEnv *,jobject,jboolean release_media_player)213 void ContentVideoView::ExitFullscreen(
214     JNIEnv*, jobject, jboolean release_media_player) {
215   power_save_blocker_.reset();
216   j_content_video_view_.reset();
217   manager_->ExitFullscreen(release_media_player);
218 }
219 
SetSurface(JNIEnv * env,jobject obj,jobject surface)220 void ContentVideoView::SetSurface(JNIEnv* env, jobject obj,
221                                   jobject surface) {
222   manager_->SetVideoSurface(
223       gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
224 }
225 
RequestMediaMetadata(JNIEnv * env,jobject obj)226 void ContentVideoView::RequestMediaMetadata(JNIEnv* env, jobject obj) {
227   base::MessageLoop::current()->PostTask(
228       FROM_HERE,
229       base::Bind(&ContentVideoView::UpdateMediaMetadata,
230                  weak_factory_.GetWeakPtr()));
231 }
232 
GetJavaObject(JNIEnv * env)233 ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
234   return j_content_video_view_.get(env);
235 }
236 
GetNativeView()237 gfx::NativeView ContentVideoView::GetNativeView() {
238   JNIEnv* env = AttachCurrentThread();
239   ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
240   if (content_video_view.is_null())
241     return NULL;
242 
243   return reinterpret_cast<gfx::NativeView>(
244       Java_ContentVideoView_getNativeViewAndroid(env,
245                                                  content_video_view.obj()));
246 
247 }
248 
CreateJavaObject()249 JavaObjectWeakGlobalRef ContentVideoView::CreateJavaObject() {
250   ContentViewCoreImpl* content_view_core = manager_->GetContentViewCore();
251   JNIEnv* env = AttachCurrentThread();
252   return JavaObjectWeakGlobalRef(
253       env,
254       Java_ContentVideoView_createContentVideoView(
255           env,
256           content_view_core->GetContext().obj(),
257           reinterpret_cast<intptr_t>(this),
258           content_view_core->GetContentVideoViewClient().obj()).obj());
259 }
260 
CreatePowerSaveBlocker()261 void ContentVideoView::CreatePowerSaveBlocker() {
262   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
263       switches::kEnableContentVideoViewPowerSaveBlocker)) {
264     // In fullscreen Clank reuses the power save blocker attached to the
265     // container view that was created for embedded video. The WebView cannot
266     // reuse that so we create a new blocker instead.
267     if (power_save_blocker_) return;
268     power_save_blocker_ = PowerSaveBlocker::Create(
269         PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
270         "Playing video").Pass();
271     static_cast<PowerSaveBlockerImpl*>(power_save_blocker_.get())->
272         InitDisplaySleepBlocker(GetNativeView());
273   }
274 }
275 
276 }  // namespace content
277