parent
730de45127
commit
5dd9798ccd
@ -0,0 +1,437 @@ |
||||
package com.github.tvbox.osc.player.controller; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.Context; |
||||
import android.media.AudioManager; |
||||
import android.os.Handler; |
||||
import android.os.Message; |
||||
import android.util.AttributeSet; |
||||
import android.view.GestureDetector; |
||||
import android.view.KeyEvent; |
||||
import android.view.MotionEvent; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.view.Window; |
||||
import android.view.WindowManager; |
||||
import android.widget.ProgressBar; |
||||
import android.widget.TextView; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.Nullable; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import xyz.doikki.videoplayer.controller.BaseVideoController; |
||||
import xyz.doikki.videoplayer.controller.IControlComponent; |
||||
import xyz.doikki.videoplayer.controller.IGestureComponent; |
||||
import xyz.doikki.videoplayer.player.VideoView; |
||||
import xyz.doikki.videoplayer.util.PlayerUtils; |
||||
|
||||
public abstract class BaseController extends BaseVideoController implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, View.OnTouchListener { |
||||
private GestureDetector mGestureDetector; |
||||
private AudioManager mAudioManager; |
||||
private boolean mIsGestureEnabled = true; |
||||
private int mStreamVolume; |
||||
private float mBrightness; |
||||
private int mSeekPosition; |
||||
private boolean mFirstTouch; |
||||
private boolean mChangePosition; |
||||
private boolean mChangeBrightness; |
||||
private boolean mChangeVolume; |
||||
private boolean mCanChangePosition = true; |
||||
private boolean mEnableInNormal; |
||||
private boolean mCanSlide; |
||||
private int mCurPlayState; |
||||
|
||||
protected Handler mHandler; |
||||
|
||||
protected HandlerCallback mHandlerCallback; |
||||
|
||||
protected interface HandlerCallback { |
||||
void callback(Message msg); |
||||
} |
||||
|
||||
private boolean mIsDoubleTapTogglePlayEnabled = true; |
||||
|
||||
|
||||
public BaseController(@NonNull Context context) { |
||||
super(context); |
||||
mHandler = new Handler(new Handler.Callback() { |
||||
@Override |
||||
public boolean handleMessage(@NonNull Message msg) { |
||||
int what = msg.what; |
||||
switch (what) { |
||||
case 100: { // 亮度+音量调整
|
||||
mSlideInfo.setVisibility(VISIBLE); |
||||
mSlideInfo.setText(msg.obj.toString()); |
||||
break; |
||||
} |
||||
|
||||
case 101: { // 亮度+音量调整 关闭
|
||||
mSlideInfo.setVisibility(GONE); |
||||
break; |
||||
} |
||||
default: { |
||||
if (mHandlerCallback != null) |
||||
mHandlerCallback.callback(msg); |
||||
break; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public BaseController(@NonNull Context context, @Nullable AttributeSet attrs) { |
||||
super(context, attrs); |
||||
} |
||||
|
||||
public BaseController(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { |
||||
super(context, attrs, defStyleAttr); |
||||
} |
||||
|
||||
TextView mSlideInfo; |
||||
ProgressBar mLoading; |
||||
ViewGroup mPauseRoot; |
||||
TextView mPauseTime; |
||||
|
||||
@Override |
||||
protected void initView() { |
||||
super.initView(); |
||||
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); |
||||
mGestureDetector = new GestureDetector(getContext(), this); |
||||
setOnTouchListener(this); |
||||
mSlideInfo = findViewWithTag("vod_control_slide_info"); |
||||
mLoading = findViewWithTag("vod_control_loading"); |
||||
mPauseRoot = findViewWithTag("vod_control_pause"); |
||||
mPauseTime = findViewWithTag("vod_control_pause_t"); |
||||
} |
||||
|
||||
@Override |
||||
protected void setProgress(int duration, int position) { |
||||
super.setProgress(duration, position); |
||||
mPauseTime.setText(PlayerUtils.stringForTime(position) + " / " + PlayerUtils.stringForTime(duration)); |
||||
} |
||||
|
||||
@Override |
||||
protected void onPlayStateChanged(int playState) { |
||||
super.onPlayStateChanged(playState); |
||||
switch (playState) { |
||||
case VideoView.STATE_IDLE: |
||||
mLoading.setVisibility(GONE); |
||||
break; |
||||
case VideoView.STATE_PLAYING: |
||||
mPauseRoot.setVisibility(GONE); |
||||
mLoading.setVisibility(GONE); |
||||
break; |
||||
case VideoView.STATE_PAUSED: |
||||
mPauseRoot.setVisibility(VISIBLE); |
||||
mLoading.setVisibility(GONE); |
||||
break; |
||||
case VideoView.STATE_PREPARED: |
||||
case VideoView.STATE_ERROR: |
||||
case VideoView.STATE_BUFFERED: |
||||
mLoading.setVisibility(GONE); |
||||
break; |
||||
case VideoView.STATE_PREPARING: |
||||
case VideoView.STATE_BUFFERING: |
||||
mLoading.setVisibility(VISIBLE); |
||||
break; |
||||
case VideoView.STATE_PLAYBACK_COMPLETED: |
||||
mLoading.setVisibility(GONE); |
||||
mPauseRoot.setVisibility(GONE); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 设置是否可以滑动调节进度,默认可以 |
||||
*/ |
||||
public void setCanChangePosition(boolean canChangePosition) { |
||||
mCanChangePosition = canChangePosition; |
||||
} |
||||
|
||||
/** |
||||
* 是否在竖屏模式下开始手势控制,默认关闭 |
||||
*/ |
||||
public void setEnableInNormal(boolean enableInNormal) { |
||||
mEnableInNormal = enableInNormal; |
||||
} |
||||
|
||||
/** |
||||
* 是否开启手势控制,默认开启,关闭之后,手势调节进度,音量,亮度功能将关闭 |
||||
*/ |
||||
public void setGestureEnabled(boolean gestureEnabled) { |
||||
mIsGestureEnabled = gestureEnabled; |
||||
} |
||||
|
||||
/** |
||||
* 是否开启双击播放/暂停,默认开启 |
||||
*/ |
||||
public void setDoubleTapTogglePlayEnabled(boolean enabled) { |
||||
mIsDoubleTapTogglePlayEnabled = enabled; |
||||
} |
||||
|
||||
@Override |
||||
public void setPlayerState(int playerState) { |
||||
super.setPlayerState(playerState); |
||||
if (playerState == VideoView.PLAYER_NORMAL) { |
||||
mCanSlide = mEnableInNormal; |
||||
} else if (playerState == VideoView.PLAYER_FULL_SCREEN) { |
||||
mCanSlide = true; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setPlayState(int playState) { |
||||
super.setPlayState(playState); |
||||
mCurPlayState = playState; |
||||
} |
||||
|
||||
protected boolean isInPlaybackState() { |
||||
return mControlWrapper != null |
||||
&& mCurPlayState != VideoView.STATE_ERROR |
||||
&& mCurPlayState != VideoView.STATE_IDLE |
||||
&& mCurPlayState != VideoView.STATE_PREPARING |
||||
&& mCurPlayState != VideoView.STATE_PREPARED |
||||
&& mCurPlayState != VideoView.STATE_START_ABORT |
||||
&& mCurPlayState != VideoView.STATE_PLAYBACK_COMPLETED; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouch(View v, MotionEvent event) { |
||||
return mGestureDetector.onTouchEvent(event); |
||||
} |
||||
|
||||
/** |
||||
* 手指按下的瞬间 |
||||
*/ |
||||
@Override |
||||
public boolean onDown(MotionEvent e) { |
||||
if (!isInPlaybackState() //不处于播放状态
|
||||
|| !mIsGestureEnabled //关闭了手势
|
||||
|| PlayerUtils.isEdge(getContext(), e)) //处于屏幕边沿
|
||||
return true; |
||||
mStreamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); |
||||
Activity activity = PlayerUtils.scanForActivity(getContext()); |
||||
if (activity == null) { |
||||
mBrightness = 0; |
||||
} else { |
||||
mBrightness = activity.getWindow().getAttributes().screenBrightness; |
||||
} |
||||
mFirstTouch = true; |
||||
mChangePosition = false; |
||||
mChangeBrightness = false; |
||||
mChangeVolume = false; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 单击 |
||||
*/ |
||||
@Override |
||||
public boolean onSingleTapConfirmed(MotionEvent e) { |
||||
if (isInPlaybackState()) { |
||||
mControlWrapper.toggleShowState(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 双击 |
||||
*/ |
||||
@Override |
||||
public boolean onDoubleTap(MotionEvent e) { |
||||
if (mIsDoubleTapTogglePlayEnabled && !isLocked() && isInPlaybackState()) togglePlay(); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 在屏幕上滑动 |
||||
*/ |
||||
@Override |
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { |
||||
if (!isInPlaybackState() //不处于播放状态
|
||||
|| !mIsGestureEnabled //关闭了手势
|
||||
|| !mCanSlide //关闭了滑动手势
|
||||
|| isLocked() //锁住了屏幕
|
||||
|| PlayerUtils.isEdge(getContext(), e1)) //处于屏幕边沿
|
||||
return true; |
||||
float deltaX = e1.getX() - e2.getX(); |
||||
float deltaY = e1.getY() - e2.getY(); |
||||
if (mFirstTouch) { |
||||
mChangePosition = Math.abs(distanceX) >= Math.abs(distanceY); |
||||
if (!mChangePosition) { |
||||
//半屏宽度
|
||||
int halfScreen = PlayerUtils.getScreenWidth(getContext(), true) / 2; |
||||
if (e2.getX() > halfScreen) { |
||||
mChangeVolume = true; |
||||
} else { |
||||
mChangeBrightness = true; |
||||
} |
||||
} |
||||
|
||||
if (mChangePosition) { |
||||
//根据用户设置是否可以滑动调节进度来决定最终是否可以滑动调节进度
|
||||
mChangePosition = mCanChangePosition; |
||||
} |
||||
|
||||
if (mChangePosition || mChangeBrightness || mChangeVolume) { |
||||
for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) { |
||||
IControlComponent component = next.getKey(); |
||||
if (component instanceof IGestureComponent) { |
||||
((IGestureComponent) component).onStartSlide(); |
||||
} |
||||
} |
||||
} |
||||
mFirstTouch = false; |
||||
} |
||||
if (mChangePosition) { |
||||
slideToChangePosition(deltaX); |
||||
} else if (mChangeBrightness) { |
||||
slideToChangeBrightness(deltaY); |
||||
} else if (mChangeVolume) { |
||||
slideToChangeVolume(deltaY); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
protected void slideToChangePosition(float deltaX) { |
||||
deltaX = -deltaX; |
||||
int width = getMeasuredWidth(); |
||||
int duration = (int) mControlWrapper.getDuration(); |
||||
int currentPosition = (int) mControlWrapper.getCurrentPosition(); |
||||
int position = (int) (deltaX / width * 120000 + currentPosition); |
||||
if (position > duration) position = duration; |
||||
if (position < 0) position = 0; |
||||
for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) { |
||||
IControlComponent component = next.getKey(); |
||||
if (component instanceof IGestureComponent) { |
||||
((IGestureComponent) component).onPositionChange(position, currentPosition, duration); |
||||
} |
||||
} |
||||
updateSeekUI(currentPosition, position, duration); |
||||
mSeekPosition = position; |
||||
} |
||||
|
||||
protected void updateSeekUI(int curr, int seekTo, int duration) { |
||||
|
||||
} |
||||
|
||||
protected void slideToChangeBrightness(float deltaY) { |
||||
Activity activity = PlayerUtils.scanForActivity(getContext()); |
||||
if (activity == null) return; |
||||
Window window = activity.getWindow(); |
||||
WindowManager.LayoutParams attributes = window.getAttributes(); |
||||
int height = getMeasuredHeight(); |
||||
if (mBrightness == -1.0f) mBrightness = 0.5f; |
||||
float brightness = deltaY * 2 / height * 1.0f + mBrightness; |
||||
if (brightness < 0) { |
||||
brightness = 0f; |
||||
} |
||||
if (brightness > 1.0f) brightness = 1.0f; |
||||
int percent = (int) (brightness * 100); |
||||
attributes.screenBrightness = brightness; |
||||
window.setAttributes(attributes); |
||||
for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) { |
||||
IControlComponent component = next.getKey(); |
||||
if (component instanceof IGestureComponent) { |
||||
((IGestureComponent) component).onBrightnessChange(percent); |
||||
} |
||||
} |
||||
Message msg = Message.obtain(); |
||||
msg.what = 100; |
||||
msg.obj = "亮度" + percent + "%"; |
||||
mHandler.sendMessage(msg); |
||||
mHandler.removeMessages(101); |
||||
mHandler.sendEmptyMessageDelayed(101, 1000); |
||||
} |
||||
|
||||
protected void slideToChangeVolume(float deltaY) { |
||||
int streamMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); |
||||
int height = getMeasuredHeight(); |
||||
float deltaV = deltaY * 2 / height * streamMaxVolume; |
||||
float index = mStreamVolume + deltaV; |
||||
if (index > streamMaxVolume) index = streamMaxVolume; |
||||
if (index < 0) index = 0; |
||||
int percent = (int) (index / streamMaxVolume * 100); |
||||
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) index, 0); |
||||
for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) { |
||||
IControlComponent component = next.getKey(); |
||||
if (component instanceof IGestureComponent) { |
||||
((IGestureComponent) component).onVolumeChange(percent); |
||||
} |
||||
} |
||||
Message msg = Message.obtain(); |
||||
msg.what = 100; |
||||
msg.obj = "音量" + percent + "%"; |
||||
mHandler.sendMessage(msg); |
||||
mHandler.removeMessages(101); |
||||
mHandler.sendEmptyMessageDelayed(101, 1000); |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent event) { |
||||
//滑动结束时事件处理
|
||||
if (!mGestureDetector.onTouchEvent(event)) { |
||||
int action = event.getAction(); |
||||
switch (action) { |
||||
case MotionEvent.ACTION_UP: |
||||
stopSlide(); |
||||
if (mSeekPosition > 0) { |
||||
mControlWrapper.seekTo(mSeekPosition); |
||||
mSeekPosition = 0; |
||||
} |
||||
break; |
||||
case MotionEvent.ACTION_CANCEL: |
||||
stopSlide(); |
||||
mSeekPosition = 0; |
||||
break; |
||||
} |
||||
} |
||||
return super.onTouchEvent(event); |
||||
} |
||||
|
||||
private void stopSlide() { |
||||
for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) { |
||||
IControlComponent component = next.getKey(); |
||||
if (component instanceof IGestureComponent) { |
||||
((IGestureComponent) component).onStopSlide(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void onLongPress(MotionEvent e) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void onShowPress(MotionEvent e) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public boolean onDoubleTapEvent(MotionEvent e) { |
||||
return false; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean onSingleTapUp(MotionEvent e) { |
||||
return false; |
||||
} |
||||
|
||||
public boolean onKeyEvent(KeyEvent event) { |
||||
if (!isInPlaybackState() //不处于播放状态
|
||||
|| isLocked() //锁住了屏幕
|
||||
) |
||||
return false; |
||||
return false; |
||||
} |
||||
} |
||||
@ -0,0 +1,225 @@ |
||||
package com.github.tvbox.osc.player.controller; |
||||
|
||||
import android.content.Context; |
||||
import android.os.Message; |
||||
import android.view.KeyEvent; |
||||
import android.view.MotionEvent; |
||||
import android.widget.ImageView; |
||||
import android.widget.LinearLayout; |
||||
import android.widget.SeekBar; |
||||
import android.widget.TextView; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
import com.github.tvbox.osc.R; |
||||
|
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
import xyz.doikki.videoplayer.player.VideoView; |
||||
import xyz.doikki.videoplayer.util.PlayerUtils; |
||||
|
||||
import static xyz.doikki.videoplayer.util.PlayerUtils.stringForTime; |
||||
|
||||
public class VodController extends BaseController { |
||||
public VodController(@NonNull @NotNull Context context) { |
||||
super(context); |
||||
mHandlerCallback = new HandlerCallback() { |
||||
@Override |
||||
public void callback(Message msg) { |
||||
switch (msg.what) { |
||||
case 1000: { // seek 刷新
|
||||
mProgressRoot.setVisibility(VISIBLE); |
||||
break; |
||||
} |
||||
case 1001: { // seek 关闭
|
||||
mProgressRoot.setVisibility(GONE); |
||||
break; |
||||
} |
||||
case 1002: { // 显示底部菜单
|
||||
mBottomRoot.setVisibility(VISIBLE); |
||||
break; |
||||
} |
||||
case 1003: { // 隐藏底部菜单
|
||||
mBottomRoot.setVisibility(GONE); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
SeekBar mSeekBar; |
||||
TextView mCurrentTime; |
||||
TextView mTotalTime; |
||||
boolean mIsDragging; |
||||
LinearLayout mProgressRoot; |
||||
TextView mProgressText; |
||||
ImageView mProgressIcon; |
||||
LinearLayout mBottomRoot; |
||||
|
||||
@Override |
||||
protected void initView() { |
||||
super.initView(); |
||||
mCurrentTime = findViewById(R.id.curr_time); |
||||
mTotalTime = findViewById(R.id.total_time); |
||||
mSeekBar = findViewById(R.id.seekBar); |
||||
mProgressRoot = findViewById(R.id.tv_progress_container); |
||||
mProgressIcon = findViewById(R.id.tv_progress_icon); |
||||
mProgressText = findViewById(R.id.tv_progress_text); |
||||
mBottomRoot = findViewById(R.id.bottom_container); |
||||
|
||||
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { |
||||
int lastProgress = 0; |
||||
|
||||
@Override |
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { |
||||
if (!fromUser) { |
||||
return; |
||||
} |
||||
|
||||
long duration = mControlWrapper.getDuration(); |
||||
long newPosition = (duration * progress) / seekBar.getMax(); |
||||
if (mCurrentTime != null) |
||||
mCurrentTime.setText(stringForTime((int) newPosition)); |
||||
} |
||||
|
||||
@Override |
||||
public void onStartTrackingTouch(SeekBar seekBar) { |
||||
mIsDragging = true; |
||||
mControlWrapper.stopProgress(); |
||||
mControlWrapper.stopFadeOut(); |
||||
} |
||||
|
||||
@Override |
||||
public void onStopTrackingTouch(SeekBar seekBar) { |
||||
long duration = mControlWrapper.getDuration(); |
||||
long newPosition = (duration * seekBar.getProgress()) / seekBar.getMax(); |
||||
mControlWrapper.seekTo((int) newPosition); |
||||
mIsDragging = false; |
||||
mControlWrapper.startProgress(); |
||||
mControlWrapper.startFadeOut(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
protected int getLayoutId() { |
||||
return R.layout.player_vod_control_view; |
||||
} |
||||
|
||||
@Override |
||||
protected void setProgress(int duration, int position) { |
||||
if (mIsDragging) { |
||||
return; |
||||
} |
||||
super.setProgress(duration, position); |
||||
mCurrentTime.setText(PlayerUtils.stringForTime(position)); |
||||
mTotalTime.setText(PlayerUtils.stringForTime(duration)); |
||||
if (duration > 0) { |
||||
mSeekBar.setEnabled(true); |
||||
int pos = (int) (position * 1.0 / duration * mSeekBar.getMax()); |
||||
mSeekBar.setProgress(pos); |
||||
} else { |
||||
mSeekBar.setEnabled(false); |
||||
} |
||||
int percent = mControlWrapper.getBufferedPercentage(); |
||||
if (percent >= 95) { |
||||
mSeekBar.setSecondaryProgress(mSeekBar.getMax()); |
||||
} else { |
||||
mSeekBar.setSecondaryProgress(percent * 10); |
||||
} |
||||
} |
||||
|
||||
private boolean simSlideStart = false; |
||||
private int simSeekPosition = 0; |
||||
private long simSlideOffset = 0; |
||||
|
||||
public void tvSlideStop() { |
||||
if (!simSlideStart) |
||||
return; |
||||
mControlWrapper.seekTo(simSeekPosition); |
||||
if (!mControlWrapper.isPlaying()) |
||||
mControlWrapper.start(); |
||||
simSlideStart = false; |
||||
simSeekPosition = 0; |
||||
simSlideOffset = 0; |
||||
} |
||||
|
||||
public void tvSlideStart(int dir) { |
||||
int duration = (int) mControlWrapper.getDuration(); |
||||
if (duration <= 0) |
||||
return; |
||||
if (!simSlideStart) { |
||||
simSlideStart = true; |
||||
} |
||||
// 每次10秒
|
||||
simSlideOffset += (10000.0f * dir); |
||||
int currentPosition = (int) mControlWrapper.getCurrentPosition(); |
||||
int position = (int) (simSlideOffset + currentPosition); |
||||
if (position > duration) position = duration; |
||||
if (position < 0) position = 0; |
||||
updateSeekUI(currentPosition, position, duration); |
||||
simSeekPosition = position; |
||||
} |
||||
|
||||
@Override |
||||
protected void updateSeekUI(int curr, int seekTo, int duration) { |
||||
super.updateSeekUI(curr, seekTo, duration); |
||||
if (seekTo > curr) { |
||||
mProgressIcon.setImageResource(R.drawable.icon_pre); |
||||
} else { |
||||
mProgressIcon.setImageResource(R.drawable.icon_back); |
||||
} |
||||
mProgressText.setText(PlayerUtils.stringForTime(seekTo) + " / " + PlayerUtils.stringForTime(duration)); |
||||
mHandler.sendEmptyMessage(1000); |
||||
mHandler.removeMessages(1001); |
||||
mHandler.sendEmptyMessageDelayed(1001, 1000); |
||||
} |
||||
|
||||
@Override |
||||
protected void onPlayStateChanged(int playState) { |
||||
super.onPlayStateChanged(playState); |
||||
switch (playState) { |
||||
case VideoView.STATE_PLAYING: |
||||
startProgress(); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean onKeyEvent(KeyEvent event) { |
||||
if (super.onKeyEvent(event)) { |
||||
return true; |
||||
} |
||||
if (isInPlaybackState()) { |
||||
int keyCode = event.getKeyCode(); |
||||
int action = event.getAction(); |
||||
if (action == KeyEvent.ACTION_DOWN) { |
||||
if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { |
||||
tvSlideStart(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : -1); |
||||
} else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { |
||||
togglePlay(); |
||||
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { |
||||
} else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { |
||||
} |
||||
} else if (action == KeyEvent.ACTION_UP) { |
||||
if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { |
||||
tvSlideStop(); |
||||
} |
||||
} |
||||
return super.dispatchKeyEvent(event); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onSingleTapConfirmed(MotionEvent e) { |
||||
if (isInPlaybackState()) { |
||||
mHandler.sendEmptyMessage(1003); |
||||
mHandler.removeMessages(1004); |
||||
mHandler.sendEmptyMessageDelayed(1004, 3000); |
||||
return true; |
||||
} |
||||
return super.onSingleTapConfirmed(e); |
||||
} |
||||
} |
||||
@ -0,0 +1,22 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<item android:id="@android:id/background"> |
||||
<shape> |
||||
<solid android:color="@color/color_6C3D3D3D" /> |
||||
</shape> |
||||
</item> |
||||
<item android:id="@android:id/secondaryProgress"> |
||||
<clip> |
||||
<shape> |
||||
<solid android:color="@color/color_CC353744" /> |
||||
</shape> |
||||
</clip> |
||||
</item> |
||||
<item android:id="@android:id/progress"> |
||||
<clip> |
||||
<shape> |
||||
<solid android:color="@color/color_353744" /> |
||||
</shape> |
||||
</clip> |
||||
</item> |
||||
</layer-list> |
||||
@ -0,0 +1,7 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<item android:drawable="@drawable/shape_player_control_vod_seek_thumb_press" android:state_focused="true" android:state_pressed="true" /> |
||||
<item android:drawable="@drawable/shape_player_control_vod_seek_thumb_press" android:state_focused="false" android:state_pressed="true" /> |
||||
<item android:drawable="@drawable/shape_player_control_vod_seek_thumb_normal" android:state_focused="true" android:state_pressed="false" /> |
||||
<item android:drawable="@drawable/shape_player_control_vod_seek_thumb_normal" /> |
||||
</selector> |
||||
@ -0,0 +1,8 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
<solid android:color="@color/color_BD0CADE2" /> |
||||
<size |
||||
android:width="@dimen/vs_30" |
||||
android:height="@dimen/vs_30" /> |
||||
</shape> |
||||
@ -0,0 +1,8 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
<solid android:color="@color/color_0CADE2" /> |
||||
<size |
||||
android:width="@dimen/vs_30" |
||||
android:height="@dimen/vs_30" /> |
||||
</shape> |
||||
@ -1,12 +0,0 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:id="@+id/rootLayout" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"> |
||||
|
||||
<xyz.doikki.videoplayer.player.VideoView |
||||
android:id="@+id/mVideoView" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" /> |
||||
|
||||
</FrameLayout> |
||||
@ -0,0 +1,322 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/bottom_container" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="bottom" |
||||
android:background="@drawable/shape_dialog_filter_bg" |
||||
android:gravity="center_vertical" |
||||
android:orientation="vertical" |
||||
android:paddingLeft="@dimen/vs_20" |
||||
android:paddingTop="@dimen/vs_20" |
||||
android:paddingRight="@dimen/vs_20" |
||||
android:paddingBottom="@dimen/vs_10" |
||||
android:visibility="gone"> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginBottom="@dimen/vs_10" |
||||
android:orientation="horizontal"> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_pre" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="上一集" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_next" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="下一集" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_player" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="系统播放器" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_ijk" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="硬解码" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_scale" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="16:9" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_speed" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="x1.0" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="片头片尾" |
||||
android:textColor="@color/color_CC000000" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_time_start" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="01:00" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_time_end" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="01:00" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/play_time_step" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginEnd="@dimen/vs_10" |
||||
android:layout_marginRight="@dimen/vs_10" |
||||
android:background="@drawable/button_dialog_main" |
||||
android:padding="@dimen/vs_10" |
||||
android:text="1S" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<com.owen.tvrecyclerview.widget.TvRecyclerView |
||||
android:id="@+id/mGridViewWord" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/vs_50" |
||||
android:layout_marginTop="@dimen/vs_10" |
||||
android:layout_marginBottom="@dimen/vs_10" |
||||
android:clipChildren="false" |
||||
android:clipToPadding="false" |
||||
android:visibility="gone" |
||||
app:tv_horizontalSpacingWithMargins="@dimen/vs_5" |
||||
app:tv_selectedItemIsCentered="true" |
||||
app:tv_verticalSpacingWithMargins="@dimen/vs_5" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginBottom="@dimen/vs_10" |
||||
android:orientation="horizontal"> |
||||
|
||||
<TextView |
||||
android:id="@+id/curr_time" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:paddingEnd="@dimen/vs_10" |
||||
android:paddingRight="@dimen/vs_10" |
||||
android:text="00:00" |
||||
android:textColor="@color/color_CC000000" |
||||
android:textSize="@dimen/ts_20" /> |
||||
|
||||
<SeekBar |
||||
android:id="@+id/seekBar" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="center" |
||||
android:layout_weight="1" |
||||
android:background="@null" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:max="1000" |
||||
android:maxHeight="@dimen/vs_6" |
||||
android:minHeight="@dimen/vs_6" |
||||
android:padding="@dimen/vs_0" |
||||
android:paddingStart="@dimen/vs_0" |
||||
android:paddingEnd="@dimen/vs_0" |
||||
android:progressDrawable="@drawable/shape_player_control_vod_seek" |
||||
android:thumb="@drawable/shape_player_control_vod_seek_thumb" |
||||
android:thumbOffset="@dimen/vs_0" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/total_time" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:paddingStart="@dimen/vs_10" |
||||
android:paddingLeft="@dimen/vs_10" |
||||
android:text="00:00" |
||||
android:textColor="@color/color_CC000000" |
||||
android:textSize="@dimen/ts_20" /> |
||||
</LinearLayout> |
||||
|
||||
|
||||
</LinearLayout> |
||||
|
||||
<FrameLayout |
||||
android:id="@+id/tv_pause_container" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:tag="vod_control_pause" |
||||
android:visibility="gone" |
||||
tools:visibility="visible"> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_info_name" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="left" |
||||
android:text="http://" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_24" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="@dimen/vs_280" |
||||
android:layout_height="@dimen/vs_200" |
||||
android:layout_gravity="center" |
||||
android:background="@drawable/shape_user_focus" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:gravity="center" |
||||
android:orientation="vertical"> |
||||
|
||||
<ImageView |
||||
android:layout_width="@dimen/vs_60" |
||||
android:layout_height="@dimen/vs_60" |
||||
android:layout_gravity="center" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:src="@drawable/icon_play" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_pause_progress_text" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="center" |
||||
android:layout_marginTop="@dimen/vs_20" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:tag="vod_control_pause_t" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_30" |
||||
tools:text="100" /> |
||||
</LinearLayout> |
||||
|
||||
</FrameLayout> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_slide_progress_text" |
||||
android:layout_width="@dimen/vs_200" |
||||
android:layout_height="@dimen/vs_100" |
||||
android:layout_gravity="center" |
||||
android:background="@drawable/shape_user_focus" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:gravity="center" |
||||
android:tag="vod_control_slide_info" |
||||
android:textAlignment="gravity" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_30" |
||||
android:visibility="gone" |
||||
tools:text="100" /> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/tv_progress_container" |
||||
android:layout_width="@dimen/vs_280" |
||||
android:layout_height="@dimen/vs_200" |
||||
android:layout_gravity="center" |
||||
android:background="@drawable/shape_user_focus" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:gravity="center" |
||||
android:orientation="vertical" |
||||
android:visibility="gone" |
||||
tools:visibility="visible"> |
||||
|
||||
<ImageView |
||||
android:id="@+id/tv_progress_icon" |
||||
android:layout_width="@dimen/vs_60" |
||||
android:layout_height="@dimen/vs_60" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
tools:src="@drawable/icon_back" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_progress_text" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="center" |
||||
android:layout_marginTop="@dimen/vs_20" |
||||
android:focusable="false" |
||||
android:focusableInTouchMode="false" |
||||
android:textColor="@android:color/white" |
||||
android:textSize="@dimen/ts_30" |
||||
tools:text="100" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<ProgressBar |
||||
android:layout_width="@dimen/vs_50" |
||||
android:layout_height="@dimen/vs_50" |
||||
android:layout_gravity="center" |
||||
android:indeterminateBehavior="repeat" |
||||
android:indeterminateDrawable="@drawable/anim_loading" |
||||
android:indeterminateOnly="true" |
||||
android:tag="vod_control_loading" /> |
||||
|
||||
</FrameLayout> |
||||
Loading…
Reference in new issue