puwei/app/src/main/java/com/yinuo/safetywatcher/player/VideoControllerView.java

607 lines
17 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.yinuo.safetywatcher.player;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.MediaController;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.yinuo.safetywatcher.R;
import java.lang.ref.WeakReference;
import java.util.Formatter;
import java.util.Locale;
import tv.danmaku.ijk.media.widget.media.IMediaController;
/**
* 播放控制器
* <p>
* Created by jiaozebo on 2017/6/11.
*/
public class VideoControllerView extends FrameLayout implements IMediaController {
private static final String TAG = "VideoControllerView";
private MediaController.MediaPlayerControl mPlayer;
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 10000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mUseFastForward;
private boolean mFromXml;
StringBuilder mFormatBuilder;
Formatter mFormatter;
private Context mContext;
private View mAnchor;
private View mRoot;
private SeekBar mProgress; // 播放进度滚动条
private TextView mCurrentTime; // 当前播放时间点
private TextView mEndTime; // 总时长
private ImageButton mPauseButton; // 暂停or开始
private ImageButton mFastButton; // 快进
private ImageButton mRewindButton; // 快退
private Handler mHandler = new MessageHandler(this);
private Runnable mSeekingPending;
// 暂停/开始的点击事件
private OnClickListener mPauseListener = v -> {
doPauseResume();
show(sDefaultTimeout);
};
// 滚动条的点击事件
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
mDragging = true;
mHandler.removeMessages(SHOW_PROGRESS);
}
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (mPlayer == null) {
return;
}
if (!fromuser) {
return;
}
if (mSeekingPending != null) {
removeCallbacks(mSeekingPending);
mSeekingPending = null;
}
if (mPlayer.getDuration() <= 0)
return;
// long duration = mPlayer.getDuration();
// long newPosition = (duration * progress) / 1000L;
mPlayer.seekTo((int) progress);
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime((int) progress));
}
public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
updatePausePlay();
show(sDefaultTimeout);
mHandler.sendEmptyMessage(SHOW_PROGRESS);
}
};
// 快退的点击事件
private OnClickListener mRewindListener = new OnClickListener() {
public void onClick(View v) {
if (mPlayer == null) {
return;
}
int pos = mPlayer.getCurrentPosition();
pos -= 5000; // милисекунд
if (pos < 0) {
pos = 0;
}
mPlayer.pause();
mPlayer.seekTo(pos);
show(sDefaultTimeout);
}
};
// 快进的点击事件
private OnClickListener mFastListener = new OnClickListener() {
public void onClick(View v) {
if (mPlayer == null) {
return;
}
int pos = mPlayer.getCurrentPosition();
pos += 10000; // милисекунд
if (pos > mPlayer.getDuration()) {
pos = mPlayer.getDuration();
}
mPlayer.pause();
mPlayer.seekTo(pos);
show(sDefaultTimeout);
}
};
/**
* ==================== constructor ====================
*/
public VideoControllerView(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = null;
mContext = context;
mUseFastForward = true;
mFromXml = true;
Log.i(TAG, TAG);
}
public VideoControllerView(Context context, boolean useFastForward) {
super(context);
mContext = context;
mUseFastForward = useFastForward;
Log.i(TAG, TAG);
}
public VideoControllerView(Context context) {
this(context, true);
Log.i(TAG, TAG);
}
/**
* ==================== system Override ====================
*/
/*
* 发生在视图实例化的过程中一般在activity的oncreate方法中并且只有在布局文件中实例化才有会这个回调
* */
@Override
public void onFinishInflate() {
super.onFinishInflate();
if (mRoot != null)
initControllerView(mRoot);
}
/*
* 当发生轨迹球事件时触发该方法(貌似轨迹球是过去手机的按键)
* */
@Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
/*
* 当发生触摸屏事件时触发该方法
* */
@Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mPlayer == null) {
return true;
}
int keyCode = event.getKeyCode();
final boolean uniqueDown = event.getRepeatCount() == 0 && event.getAction() == KeyEvent.ACTION_DOWN;
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
keyCode == KeyEvent.KEYCODE_SPACE) {
if (uniqueDown) {
doPauseResume();
show(sDefaultTimeout);
if (mPauseButton != null) {
mPauseButton.requestFocus();
}
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (uniqueDown && !mPlayer.isPlaying()) {
mPlayer.start();
updatePausePlay();
show(sDefaultTimeout);
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (uniqueDown && mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
show(sDefaultTimeout);
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
if (uniqueDown) {
hide();
}
return true;
}
show(sDefaultTimeout);
return super.dispatchKeyEvent(event);
}
/**
* ==================== IMediaController ====================
*/
@Override
public void hide() {
if (mAnchor == null) {
return;
}
try {
if (mAnchor instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) mAnchor;
vg.removeView(this);
}
mHandler.removeMessages(SHOW_PROGRESS);
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
}
mShowing = false;
}
public boolean isShowing() {
return mShowing;
}
@Override
public void setAnchorView(View view) {
mAnchor = view;
LayoutParams frameParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
@Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFastButton != null) {
mFastButton.setEnabled(enabled);
}
if (mRewindButton != null) {
mRewindButton.setEnabled(enabled);
}
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
disableUnsupportedButtons();
super.setEnabled(enabled);
}
@Override
public void setMediaPlayer(MediaController.MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
@Override
public void show() {
show(sDefaultTimeout);
}
@Override
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
if (mPauseButton != null) {
mPauseButton.requestFocus();
}
disableUnsupportedButtons();
LayoutParams tlp = new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.BOTTOM);
if (mAnchor instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) mAnchor;
vg.addView(this, tlp);
}
mShowing = true;
}
updatePausePlay();
mHandler.sendEmptyMessage(SHOW_PROGRESS);
Message msg = mHandler.obtainMessage(FADE_OUT);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(msg, timeout);
}
}
@Override
public void showOnce(View view) {
}
/** ==================== UI操作 ==================== */
/**
* 生成播放控制的布局
*/
protected View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = inflate.inflate(R.layout.media_controller, null);
initControllerView(mRoot);
return mRoot;
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v.findViewById(R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mFastButton = (ImageButton) v.findViewById(R.id.fast_forward);
if (mFastButton != null) {
mFastButton.setOnClickListener(mFastListener);
if (!mFromXml) {
mFastButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
mRewindButton = (ImageButton) v.findViewById(R.id.rewind);
if (mRewindButton != null) {
mRewindButton.setOnClickListener(mRewindListener);
if (!mFromXml) {
mRewindButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
mProgress = (SeekBar) v.findViewById(R.id.media_controller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(R.id.total_time);
mCurrentTime = (TextView) v.findViewById(R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
if (!mPlayer.canSeekBackward() || !mPlayer.canSeekForward()) {
v.findViewById(R.id.seek_bar_container).setVisibility(GONE);
} else {
v.findViewById(R.id.seek_bar_container).setVisibility(VISIBLE);
}
}
/**
* Отключить паузу или seek button, если поток не может быть приостановлена
* Это требует интерфейс управления MediaPlayerControlExt
*/
private void disableUnsupportedButtons() {
if (mPlayer == null) {
return;
}
try {
if (mPauseButton != null && !mPlayer.canPause()) {
mPauseButton.setEnabled(false);
}
if (mRewindButton != null && !mPlayer.canSeekBackward()) {
mRewindButton.setEnabled(false);
}
if (mFastButton != null && !mPlayer.canSeekForward()) {
mFastButton.setEnabled(false);
}
} catch (IncompatibleClassChangeError ex) {
//выводите в лог что хотите из ex
}
}
public void fastVideo() {
mFastButton.performClick();
}
public void rewindVideo() {
mRewindButton.performClick();
}
/*
* 暂停/开始播放
* */
private void doPauseResume() {
if (mPlayer == null) {
return;
}
if (mPlayer.isPlaying()) {
mPlayer.pause();
} else {
mPlayer.start();
}
updatePausePlay();
}
public void updatePausePlay() {
if (mRoot == null || mPauseButton == null || mPlayer == null) {
return;
}
if (mPlayer.isPlaying()) {
if (this.mPlayer instanceof FullScreenAbleMediaPlayerControl) {
mPauseButton.setImageResource(R.drawable.new_stop_white);
} else {
mPauseButton.setImageResource(R.drawable.new_stop);
}
} else {
if (this.mPlayer instanceof FullScreenAbleMediaPlayerControl) {
mPauseButton.setImageResource(R.drawable.new_play_white);
} else {
mPauseButton.setImageResource(R.drawable.new_play);
}
}
}
private int setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
int position = (int) (mPlayer.getCurrentPosition());
// 非文件流的duration为0.
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
int max = mProgress.getMax();
if (max != duration) {
mProgress.setMax(duration);
mProgress.setProgress(position);
} else {
mProgress.setProgress(position);
}
} else {
mProgress.setMax(0);
mProgress.setProgress(0);
}
// int percent = mPlayer.getBufferPercentage();
// mProgress.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
return position;
}
private void doToggleFullscreen() {
if (mPlayer == null) {
return;
}
if (this.mPlayer instanceof FullScreenAbleMediaPlayerControl) {
FullScreenAbleMediaPlayerControl mPlayer = (FullScreenAbleMediaPlayerControl) this.mPlayer;
mPlayer.toggleFullScreen();
}
}
private String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
public interface FullScreenAbleMediaPlayerControl extends MediaController.MediaPlayerControl {
void toggleFullScreen();
}
private static class MessageHandler extends Handler {
private final WeakReference<VideoControllerView> mView;
MessageHandler(VideoControllerView view) {
mView = new WeakReference<VideoControllerView>(view);
}
@Override
public void handleMessage(Message msg) {
VideoControllerView view = mView.get();
if (view == null || view.mPlayer == null) {
return;
}
switch (msg.what) {
case FADE_OUT:
view.hide();
break;
case SHOW_PROGRESS:
if (!view.mDragging && view.mShowing) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (view.setProgress() % 1000));
}
break;
}
}
}
}