Home | History | Annotate | Download | only in android
      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 
     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 
     41 bool ContentVideoView::RegisterContentVideoView(JNIEnv* env) {
     42   return RegisterNativesImpl(env);
     43 }
     44 
     45 ContentVideoView* ContentVideoView::GetInstance() {
     46   return g_content_video_view;
     47 }
     48 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    174 int ContentVideoView::GetVideoWidth(JNIEnv*, jobject obj) const {
    175   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
    176   return player ? player->GetVideoWidth() : 0;
    177 }
    178 
    179 int ContentVideoView::GetVideoHeight(JNIEnv*, jobject obj) const {
    180   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
    181   return player ? player->GetVideoHeight() : 0;
    182 }
    183 
    184 int ContentVideoView::GetDurationInMilliSeconds(JNIEnv*, jobject obj) const {
    185   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
    186   return player ? player->GetDuration().InMilliseconds() : -1;
    187 }
    188 
    189 int ContentVideoView::GetCurrentPosition(JNIEnv*, jobject obj) const {
    190   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
    191   return player ? player->GetCurrentTime().InMilliseconds() : 0;
    192 }
    193 
    194 bool ContentVideoView::IsPlaying(JNIEnv*, jobject obj) {
    195   media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
    196   return player ? player->IsPlaying() : false;
    197 }
    198 
    199 void ContentVideoView::SeekTo(JNIEnv*, jobject obj, jint msec) {
    200   manager_->FullscreenPlayerSeek(msec);
    201 }
    202 
    203 void ContentVideoView::Play(JNIEnv*, jobject obj) {
    204   CreatePowerSaveBlocker();
    205   manager_->FullscreenPlayerPlay();
    206 }
    207 
    208 void ContentVideoView::Pause(JNIEnv*, jobject obj) {
    209   power_save_blocker_.reset();
    210   manager_->FullscreenPlayerPause();
    211 }
    212 
    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 
    220 void ContentVideoView::SetSurface(JNIEnv* env, jobject obj,
    221                                   jobject surface) {
    222   manager_->SetVideoSurface(
    223       gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
    224 }
    225 
    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 
    233 ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
    234   return j_content_video_view_.get(env);
    235 }
    236 
    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 
    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 
    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