1// Copyright 2014 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 5package org.chromium.content.browser; 6 7import android.content.Context; 8import android.graphics.Color; 9import android.view.KeyEvent; 10import android.view.MotionEvent; 11import android.view.SurfaceHolder; 12import android.view.SurfaceView; 13import android.view.View; 14import android.widget.MediaController; 15 16/** 17 * Adds Android media controller to ContentVideoView. 18 * The sole purpose of this class is to maintain legacy behavior while we test 19 * the blink-based media controller. 20 * https://code.google.com/p/chromium/issues/detail?id=331966 21 */ 22public class ContentVideoViewLegacy extends ContentVideoView { 23 private FullScreenMediaController mMediaController; 24 private boolean mCanPause; 25 private boolean mCanSeekBackward; 26 private boolean mCanSeekForward; 27 private int mCurrentBufferPercentage; 28 private MediaControlsVisibilityListener mListener; 29 30 /** 31 * A listener for changes in the MediaController visibility. 32 */ 33 public interface MediaControlsVisibilityListener { 34 /** 35 * Callback for when the visibility of the media controls changes. 36 * 37 * @param shown true if the media controls are shown to the user, false otherwise 38 */ 39 public void onMediaControlsVisibilityChanged(boolean shown); 40 } 41 42 private static class FullScreenMediaController extends MediaController { 43 44 final View mVideoView; 45 final MediaControlsVisibilityListener mListener; 46 47 /** 48 * @param context The context. 49 * @param video The full screen video container view. 50 * @param listener A listener that listens to the visibility of media controllers. 51 */ 52 public FullScreenMediaController( 53 Context context, 54 View video, 55 MediaControlsVisibilityListener listener) { 56 super(context); 57 mVideoView = video; 58 mListener = listener; 59 } 60 61 @Override 62 public void show() { 63 super.show(); 64 if (mListener != null) mListener.onMediaControlsVisibilityChanged(true); 65 if (mVideoView != null) { 66 mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); 67 } 68 } 69 70 @Override 71 public void hide() { 72 if (mVideoView != null) { 73 mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); 74 } 75 if (mListener != null) mListener.onMediaControlsVisibilityChanged(false); 76 super.hide(); 77 } 78 } 79 80 ContentVideoViewLegacy(Context context, long nativeContentVideoView, 81 ContentVideoViewClient client) { 82 super(context, nativeContentVideoView, client); 83 setBackgroundColor(Color.BLACK); 84 mCurrentBufferPercentage = 0; 85 } 86 87 @Override 88 protected void showContentVideoView() { 89 SurfaceView surfaceView = getSurfaceView(); 90 surfaceView.setZOrderOnTop(true); 91 surfaceView.setOnKeyListener(new OnKeyListener() { 92 @Override 93 public boolean onKey(View v, int keyCode, KeyEvent event) { 94 boolean isKeyCodeSupported = ( 95 keyCode != KeyEvent.KEYCODE_BACK && 96 keyCode != KeyEvent.KEYCODE_VOLUME_UP && 97 keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && 98 keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && 99 keyCode != KeyEvent.KEYCODE_CALL && 100 keyCode != KeyEvent.KEYCODE_MENU && 101 keyCode != KeyEvent.KEYCODE_SEARCH && 102 keyCode != KeyEvent.KEYCODE_ENDCALL); 103 if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { 104 if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || 105 keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { 106 if (isPlaying()) { 107 pause(); 108 mMediaController.show(); 109 } else { 110 start(); 111 mMediaController.hide(); 112 } 113 return true; 114 } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { 115 if (!isPlaying()) { 116 start(); 117 mMediaController.hide(); 118 } 119 return true; 120 } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP 121 || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { 122 if (isPlaying()) { 123 pause(); 124 mMediaController.show(); 125 } 126 return true; 127 } else { 128 toggleMediaControlsVisiblity(); 129 } 130 } else if (keyCode == KeyEvent.KEYCODE_BACK && 131 event.getAction() == KeyEvent.ACTION_UP) { 132 exitFullscreen(false); 133 return true; 134 } else if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SEARCH) { 135 return true; 136 } 137 return false; 138 } 139 }); 140 setOnTouchListener(new OnTouchListener() { 141 @Override 142 public boolean onTouch(View v, MotionEvent event) { 143 if (isInPlaybackState() && mMediaController != null && 144 event.getAction() == MotionEvent.ACTION_DOWN) { 145 toggleMediaControlsVisiblity(); 146 } 147 return true; 148 } 149 }); 150 surfaceView.setFocusable(true); 151 surfaceView.setFocusableInTouchMode(true); 152 surfaceView.requestFocus(); 153 super.showContentVideoView(); 154 } 155 156 @Override 157 public void onMediaPlayerError(int errorType) { 158 super.onMediaPlayerError(errorType); 159 if (errorType == MEDIA_ERROR_INVALID_CODE) return; 160 if (mMediaController != null) mMediaController.hide(); 161 } 162 163 @Override 164 protected void onBufferingUpdate(int percent) { 165 super.onBufferingUpdate(percent); 166 mCurrentBufferPercentage = percent; 167 } 168 169 @Override 170 protected void onUpdateMediaMetadata( 171 int videoWidth, 172 int videoHeight, 173 int duration, 174 boolean canPause, 175 boolean canSeekBack, 176 boolean canSeekForward) { 177 super.onUpdateMediaMetadata(videoWidth, videoHeight, duration, 178 canPause, canSeekBack, canSeekForward); 179 mCanPause = canPause; 180 mCanSeekBackward = canSeekBack; 181 mCanSeekForward = canSeekForward; 182 183 if (mMediaController == null) return; 184 185 mMediaController.setEnabled(true); 186 // If paused , should show the controller forever. 187 if (isPlaying()) { 188 mMediaController.show(); 189 } else { 190 mMediaController.show(0); 191 } 192 } 193 194 @Override 195 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 196 super.surfaceChanged(holder, format, width, height); 197 SurfaceView surfaceView = getSurfaceView(); 198 surfaceView.setFocusable(true); 199 surfaceView.setFocusableInTouchMode(true); 200 if (isInPlaybackState() && mMediaController != null) { 201 mMediaController.show(); 202 } 203 } 204 205 @Override 206 protected void openVideo() { 207 super.openVideo(); 208 209 mCurrentBufferPercentage = 0; 210 211 if (mMediaController != null) return; 212 mMediaController = new FullScreenMediaController(getContext(), this, mListener); 213 mMediaController.setMediaPlayer(new MediaController.MediaPlayerControl() { 214 @Override public boolean canPause() { return mCanPause; } 215 @Override public boolean canSeekBackward() { return mCanSeekBackward; } 216 @Override public boolean canSeekForward() { return mCanSeekForward; } 217 @Override public int getAudioSessionId() { return 0; } 218 @Override public int getBufferPercentage() { return mCurrentBufferPercentage; } 219 220 @Override 221 public int getCurrentPosition() { 222 return ContentVideoViewLegacy.this.getCurrentPosition(); 223 } 224 225 @Override 226 public int getDuration() { 227 return ContentVideoViewLegacy.this.getDuration(); 228 } 229 230 @Override 231 public boolean isPlaying() { 232 return ContentVideoViewLegacy.this.isPlaying(); 233 } 234 235 @Override 236 public void pause() { 237 ContentVideoViewLegacy.this.pause(); 238 } 239 240 @Override 241 public void seekTo(int pos) { 242 ContentVideoViewLegacy.this.seekTo(pos); 243 } 244 245 @Override 246 public void start() { 247 ContentVideoViewLegacy.this.start(); 248 } 249 }); 250 mMediaController.setAnchorView(getSurfaceView()); 251 mMediaController.setEnabled(false); 252 } 253 254 @Override 255 protected void onCompletion() { 256 super.onCompletion(); 257 if (mMediaController != null) { 258 mMediaController.hide(); 259 } 260 } 261 262 @Override 263 public boolean onTrackballEvent(MotionEvent ev) { 264 if (isInPlaybackState() && mMediaController != null) { 265 toggleMediaControlsVisiblity(); 266 } 267 return false; 268 } 269 270 private void toggleMediaControlsVisiblity() { 271 if (mMediaController.isShowing()) { 272 mMediaController.hide(); 273 } else { 274 mMediaController.show(); 275 } 276 } 277 278 @Override 279 protected void destroyContentVideoView(boolean nativeViewDestroyed) { 280 if (mMediaController != null) { 281 mMediaController.setEnabled(false); 282 mMediaController.hide(); 283 mMediaController = null; 284 } 285 super.destroyContentVideoView(nativeViewDestroyed); 286 } 287 288 @Override 289 public boolean onTouchEvent(MotionEvent ev) { 290 return true; 291 } 292 293 /** 294 * Sets the MediaControlsVisibilityListener that wants to listen to visibility change events. 295 * 296 * @param listener the listener to send the events to. 297 */ 298 public void setListener(MediaControlsVisibilityListener listener) { 299 mListener = listener; 300 } 301 302} 303