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