// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.content.browser;
import android.content.Context;
import android.graphics.Color;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.MediaController;
/**
* Adds Android media controller to ContentVideoView.
* The sole purpose of this class is to maintain legacy behavior while we test
* the blink-based media controller.
* https://code.google.com/p/chromium/issues/detail?id=331966
*/
public class ContentVideoViewLegacy extends ContentVideoView {
private FullScreenMediaController mMediaController;
private boolean mCanPause;
private boolean mCanSeekBackward;
private boolean mCanSeekForward;
private int mCurrentBufferPercentage;
private MediaControlsVisibilityListener mListener;
/**
* A listener for changes in the MediaController visibility.
*/
public interface MediaControlsVisibilityListener {
/**
* Callback for when the visibility of the media controls changes.
*
* @param shown true if the media controls are shown to the user, false otherwise
*/
public void onMediaControlsVisibilityChanged(boolean shown);
}
private static class FullScreenMediaController extends MediaController {
final View mVideoView;
final MediaControlsVisibilityListener mListener;
/**
* @param context The context.
* @param video The full screen video container view.
* @param listener A listener that listens to the visibility of media controllers.
*/
public FullScreenMediaController(
Context context,
View video,
MediaControlsVisibilityListener listener) {
super(context);
mVideoView = video;
mListener = listener;
}
@Override
public void show() {
super.show();
if (mListener != null) mListener.onMediaControlsVisibilityChanged(true);
if (mVideoView != null) {
mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
@Override
public void hide() {
if (mVideoView != null) {
mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
if (mListener != null) mListener.onMediaControlsVisibilityChanged(false);
super.hide();
}
}
ContentVideoViewLegacy(Context context, long nativeContentVideoView,
ContentVideoViewClient client) {
super(context, nativeContentVideoView, client);
setBackgroundColor(Color.BLACK);
mCurrentBufferPercentage = 0;
}
@Override
protected void showContentVideoView() {
SurfaceView surfaceView = getSurfaceView();
surfaceView.setZOrderOnTop(true);
surfaceView.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
boolean isKeyCodeSupported = (
keyCode != KeyEvent.KEYCODE_BACK &&
keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
keyCode != KeyEvent.KEYCODE_CALL &&
keyCode != KeyEvent.KEYCODE_MENU &&
keyCode != KeyEvent.KEYCODE_SEARCH &&
keyCode != KeyEvent.KEYCODE_ENDCALL);
if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (isPlaying()) {
pause();
mMediaController.show();
} else {
start();
mMediaController.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (!isPlaying()) {
start();
mMediaController.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (isPlaying()) {
pause();
mMediaController.show();
}
return true;
} else {
toggleMediaControlsVisiblity();
}
} else if (keyCode == KeyEvent.KEYCODE_BACK &&
event.getAction() == KeyEvent.ACTION_UP) {
exitFullscreen(false);
return true;
} else if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SEARCH) {
return true;
}
return false;
}
});
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isInPlaybackState() && mMediaController != null &&
event.getAction() == MotionEvent.ACTION_DOWN) {
toggleMediaControlsVisiblity();
}
return true;
}
});
surfaceView.setFocusable(true);
surfaceView.setFocusableInTouchMode(true);
surfaceView.requestFocus();
super.showContentVideoView();
}
@Override
public void onMediaPlayerError(int errorType) {
super.onMediaPlayerError(errorType);
if (errorType == MEDIA_ERROR_INVALID_CODE) return;
if (mMediaController != null) mMediaController.hide();
}
@Override
protected void onBufferingUpdate(int percent) {
super.onBufferingUpdate(percent);
mCurrentBufferPercentage = percent;
}
@Override
protected void onUpdateMediaMetadata(
int videoWidth,
int videoHeight,
int duration,
boolean canPause,
boolean canSeekBack,
boolean canSeekForward) {
super.onUpdateMediaMetadata(videoWidth, videoHeight, duration,
canPause, canSeekBack, canSeekForward);
mCanPause = canPause;
mCanSeekBackward = canSeekBack;
mCanSeekForward = canSeekForward;
if (mMediaController == null) return;
mMediaController.setEnabled(true);
// If paused , should show the controller forever.
if (isPlaying()) {
mMediaController.show();
} else {
mMediaController.show(0);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.surfaceChanged(holder, format, width, height);
SurfaceView surfaceView = getSurfaceView();
surfaceView.setFocusable(true);
surfaceView.setFocusableInTouchMode(true);
if (isInPlaybackState() && mMediaController != null) {
mMediaController.show();
}
}
@Override
protected void openVideo() {
super.openVideo();
mCurrentBufferPercentage = 0;
if (mMediaController != null) return;
mMediaController = new FullScreenMediaController(getContext(), this, mListener);
mMediaController.setMediaPlayer(new MediaController.MediaPlayerControl() {
@Override public boolean canPause() { return mCanPause; }
@Override public boolean canSeekBackward() { return mCanSeekBackward; }
@Override public boolean canSeekForward() { return mCanSeekForward; }
@Override public int getAudioSessionId() { return 0; }
@Override public int getBufferPercentage() { return mCurrentBufferPercentage; }
@Override
public int getCurrentPosition() {
return ContentVideoViewLegacy.this.getCurrentPosition();
}
@Override
public int getDuration() {
return ContentVideoViewLegacy.this.getDuration();
}
@Override
public boolean isPlaying() {
return ContentVideoViewLegacy.this.isPlaying();
}
@Override
public void pause() {
ContentVideoViewLegacy.this.pause();
}
@Override
public void seekTo(int pos) {
ContentVideoViewLegacy.this.seekTo(pos);
}
@Override
public void start() {
ContentVideoViewLegacy.this.start();
}
});
mMediaController.setAnchorView(getSurfaceView());
mMediaController.setEnabled(false);
}
@Override
protected void onCompletion() {
super.onCompletion();
if (mMediaController != null) {
mMediaController.hide();
}
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
}
private void toggleMediaControlsVisiblity() {
if (mMediaController.isShowing()) {
mMediaController.hide();
} else {
mMediaController.show();
}
}
@Override
protected void destroyContentVideoView(boolean nativeViewDestroyed) {
if (mMediaController != null) {
mMediaController.setEnabled(false);
mMediaController.hide();
mMediaController = null;
}
super.destroyContentVideoView(nativeViewDestroyed);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return true;
}
/**
* Sets the MediaControlsVisibilityListener that wants to listen to visibility change events.
*
* @param listener the listener to send the events to.
*/
public void setListener(MediaControlsVisibilityListener listener) {
mListener = listener;
}
}