VideoPlayerController.java 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. package org.yczbj.ycvideoplayerlib.controller;
  2. import android.content.BroadcastReceiver;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.content.IntentFilter;
  6. import android.net.ConnectivityManager;
  7. import android.net.NetworkInfo;
  8. import android.os.BatteryManager;
  9. import android.os.CountDownTimer;
  10. import android.support.annotation.DrawableRes;
  11. import android.view.LayoutInflater;
  12. import android.view.MotionEvent;
  13. import android.view.View;
  14. import android.widget.FrameLayout;
  15. import android.widget.ImageView;
  16. import android.widget.LinearLayout;
  17. import android.widget.ProgressBar;
  18. import android.widget.SeekBar;
  19. import android.widget.TextView;
  20. import android.widget.Toast;
  21. import org.yczbj.ycvideoplayerlib.dialog.ChangeClarityDialog;
  22. import org.yczbj.ycvideoplayerlib.R;
  23. import org.yczbj.ycvideoplayerlib.dialog.VideoClarity;
  24. import org.yczbj.ycvideoplayerlib.utils.VideoLogUtil;
  25. import org.yczbj.ycvideoplayerlib.utils.VideoPlayerUtils;
  26. import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
  27. import org.yczbj.ycvideoplayerlib.inter.InterVideoPlayer;
  28. import org.yczbj.ycvideoplayerlib.inter.listener.OnClarityChangedListener;
  29. import org.yczbj.ycvideoplayerlib.inter.listener.OnCompletedListener;
  30. import org.yczbj.ycvideoplayerlib.inter.listener.OnPlayOrPauseListener;
  31. import org.yczbj.ycvideoplayerlib.inter.listener.OnVideoBackListener;
  32. import org.yczbj.ycvideoplayerlib.inter.listener.OnVideoControlListener;
  33. import java.text.SimpleDateFormat;
  34. import java.util.ArrayList;
  35. import java.util.Date;
  36. import java.util.List;
  37. import java.util.Locale;
  38. /**
  39. * <pre>
  40. * @author yangchong
  41. * blog : https://github.com/yangchong211
  42. * time : 2017/9/29
  43. * desc : 播放器控制器,主要是处理UI操作逻辑
  44. * revise: 注意:建议先判断状态,再进行设置参数
  45. * </pre>
  46. */
  47. public class VideoPlayerController extends AbsVideoPlayerController implements View.OnClickListener{
  48. private Context mContext;
  49. private ImageView mImage;
  50. private ImageView mCenterStart;
  51. private LinearLayout mTop;
  52. private ImageView mBack;
  53. private TextView mTitle;
  54. private LinearLayout mLlTopOther;
  55. private ImageView mIvDownload;
  56. private ImageView mIvAudio;
  57. private ImageView mIvShare;
  58. private ImageView mIvMenu;
  59. private LinearLayout mLlHorizontal;
  60. private ImageView mIvHorAudio;
  61. private ImageView mIvHorTv;
  62. private ImageView mBattery;
  63. private TextView mTime;
  64. private LinearLayout mBottom;
  65. private ImageView mRestartPause;
  66. private TextView mPosition;
  67. private TextView mDuration;
  68. private SeekBar mSeek;
  69. private TextView mClarity;
  70. private ImageView mFullScreen;
  71. private TextView mLength;
  72. private LinearLayout mLoading;
  73. private ProgressBar pbLoadingRing;
  74. private ProgressBar pbLoadingQq;
  75. private TextView mLoadText;
  76. private LinearLayout mChangePosition;
  77. private TextView mChangePositionCurrent;
  78. private ProgressBar mChangePositionProgress;
  79. private LinearLayout mChangeBrightness;
  80. private ProgressBar mChangeBrightnessProgress;
  81. private LinearLayout mChangeVolume;
  82. private ProgressBar mChangeVolumeProgress;
  83. private LinearLayout mError;
  84. private TextView mRetry;
  85. private LinearLayout mCompleted;
  86. private TextView mReplay;
  87. private TextView mShare;
  88. private FrameLayout mFlLock;
  89. private ImageView mIvLock;
  90. private boolean topBottomVisible;
  91. /**
  92. * 倒计时器
  93. */
  94. private CountDownTimer mDismissTopBottomCountDownTimer;
  95. private List<VideoClarity> clarities;
  96. private int defaultClarityIndex;
  97. private ChangeClarityDialog mClarityDialog;
  98. /**
  99. * 是否已经注册了电池广播
  100. */
  101. private boolean hasRegisterBatteryReceiver;
  102. /**
  103. * 是否已经注册了网络监听广播,添加这个判断可以避免崩溃
  104. */
  105. private boolean hasRegisterNetReceiver;
  106. /**
  107. * 是否锁屏
  108. */
  109. private boolean mIsLock = false;
  110. /**
  111. * 这个是time时间不操作界面,则自动隐藏顶部和底部视图布局
  112. */
  113. private long time;
  114. /**
  115. * 顶部的布局,下载,切换音频,分享布局是否显示。
  116. * 默认为false,不显示
  117. */
  118. private boolean mIsTopAndBottomVisibility = false;
  119. /**
  120. * 设置视频播放器中间的播放键是否显示
  121. * 默认为false,不显示
  122. */
  123. private boolean mIsCenterPlayerVisibility = false;
  124. /**
  125. * 网络变化监听广播,在网络变更时进行对应处理
  126. */
  127. private NetChangedReceiver netChangedReceiver;
  128. private class NetChangedReceiver extends BroadcastReceiver {
  129. private String getConnectionType(int type) {
  130. String connType = "";
  131. if (type == ConnectivityManager.TYPE_MOBILE) {
  132. connType = "3G,4G网络数据";
  133. } else if (type == ConnectivityManager.TYPE_WIFI) {
  134. connType = "WIFI网络";
  135. }
  136. return connType;
  137. }
  138. @Override
  139. public void onReceive(Context context, Intent intent) {
  140. // 监听网络连接,包括wifi和移动数据的打开和关闭,以及连接上可用的连接都会接到监听
  141. if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
  142. //获取联网状态的NetworkInfo对象
  143. NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
  144. if (info != null) {
  145. //如果当前的网络连接成功并且网络连接可用
  146. if (NetworkInfo.State.CONNECTED == info.getState() && info.isAvailable()) {
  147. if (info.getType() == ConnectivityManager.TYPE_WIFI || info.getType() == ConnectivityManager.TYPE_MOBILE) {
  148. VideoLogUtil.i(getConnectionType(info.getType()) + "连上");
  149. }
  150. } else {
  151. VideoLogUtil.i(getConnectionType(info.getType()) + "断开");
  152. onPlayStateChanged(ConstantKeys.CurrentState.STATE_ERROR);
  153. if(mVideoPlayer.isIdle()){
  154. mVideoPlayer.pause();
  155. }
  156. }
  157. }
  158. }
  159. }
  160. }
  161. /**
  162. * 电池状态即电量变化广播接收器
  163. */
  164. private BroadcastReceiver mBatterReceiver = new BroadcastReceiver() {
  165. @Override
  166. public void onReceive(Context context, Intent intent) {
  167. int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
  168. if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
  169. // 充电中
  170. mBattery.setImageResource(R.drawable.battery_charging);
  171. } else if (status == BatteryManager.BATTERY_STATUS_FULL) {
  172. // 充电完成
  173. mBattery.setImageResource(R.drawable.battery_full);
  174. } else {
  175. int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
  176. int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
  177. int percentage = (int) (((float) level / scale) * 100);
  178. if (percentage <= 10) {
  179. mBattery.setImageResource(R.drawable.battery_10);
  180. } else if (percentage <= 20) {
  181. mBattery.setImageResource(R.drawable.battery_20);
  182. } else if (percentage <= 50) {
  183. mBattery.setImageResource(R.drawable.battery_50);
  184. } else if (percentage <= 80) {
  185. mBattery.setImageResource(R.drawable.battery_80);
  186. } else if (percentage <= 100) {
  187. mBattery.setImageResource(R.drawable.battery_100);
  188. }
  189. }
  190. }
  191. };
  192. public VideoPlayerController(Context context) {
  193. super(context);
  194. mContext = context;
  195. init();
  196. }
  197. private void registerNetChangedReceiver() {
  198. if (!hasRegisterNetReceiver) {
  199. if (netChangedReceiver == null) {
  200. netChangedReceiver = new NetChangedReceiver();
  201. IntentFilter filter = new IntentFilter();
  202. filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
  203. mContext.registerReceiver(netChangedReceiver, filter);
  204. VideoLogUtil.i("注册网络监听广播");
  205. }
  206. hasRegisterNetReceiver = true;
  207. }
  208. }
  209. private void unRegisterNetChangedReceiver() {
  210. if (hasRegisterNetReceiver) {
  211. if (netChangedReceiver != null) {
  212. mContext.unregisterReceiver(netChangedReceiver);
  213. VideoLogUtil.i("解绑注册网络监听广播");
  214. }
  215. hasRegisterNetReceiver = false;
  216. }
  217. }
  218. /**
  219. * 初始化操作
  220. */
  221. private void init() {
  222. LayoutInflater.from(mContext).inflate(R.layout.custom_video_player, this, true);
  223. initFindViewById();
  224. initListener();
  225. registerNetChangedReceiver();
  226. }
  227. private void initFindViewById() {
  228. mCenterStart = findViewById(R.id.center_start);
  229. mImage = findViewById(R.id.image);
  230. mTop = findViewById(R.id.top);
  231. mBack = findViewById(R.id.back);
  232. mTitle = findViewById(R.id.title);
  233. mLlTopOther = findViewById(R.id.ll_top_other);
  234. mIvDownload = findViewById(R.id.iv_download);
  235. mIvAudio = findViewById(R.id.iv_audio);
  236. mIvShare = findViewById(R.id.iv_share);
  237. mIvMenu = findViewById(R.id.iv_menu);
  238. mLlHorizontal = findViewById(R.id.ll_horizontal);
  239. mIvHorAudio = findViewById(R.id.iv_hor_audio);
  240. mIvHorTv = findViewById(R.id.iv_hor_tv);
  241. mBattery = findViewById(R.id.battery);
  242. mTime = findViewById(R.id.time);
  243. mBottom = findViewById(R.id.bottom);
  244. mRestartPause = findViewById(R.id.restart_or_pause);
  245. mPosition = findViewById(R.id.position);
  246. mDuration = findViewById(R.id.duration);
  247. mSeek = findViewById(R.id.seek);
  248. mFullScreen = findViewById(R.id.full_screen);
  249. mClarity = findViewById(R.id.clarity);
  250. mLength = findViewById(R.id.length);
  251. mLoading = findViewById(R.id.loading);
  252. pbLoadingRing = findViewById(R.id.pb_loading_ring);
  253. pbLoadingQq = findViewById(R.id.pb_loading_qq);
  254. mLoadText = findViewById(R.id.load_text);
  255. mChangePosition = findViewById(R.id.change_position);
  256. mChangePositionCurrent = findViewById(R.id.change_position_current);
  257. mChangePositionProgress = findViewById(R.id.change_position_progress);
  258. mChangeBrightness = findViewById(R.id.change_brightness);
  259. mChangeBrightnessProgress = findViewById(R.id.change_brightness_progress);
  260. mChangeVolume = findViewById(R.id.change_volume);
  261. mChangeVolumeProgress = findViewById(R.id.change_volume_progress);
  262. mError = findViewById(R.id.error);
  263. mRetry = findViewById(R.id.retry);
  264. mCompleted = findViewById(R.id.completed);
  265. mReplay = findViewById(R.id.replay);
  266. mShare = findViewById(R.id.share);
  267. mFlLock = findViewById(R.id.fl_lock);
  268. mIvLock = findViewById(R.id.iv_lock);
  269. setTopVisibility(mIsTopAndBottomVisibility);
  270. }
  271. private void initListener() {
  272. mCenterStart.setOnClickListener(this);
  273. mBack.setOnClickListener(this);
  274. mIvDownload.setOnClickListener(this);
  275. mIvShare.setOnClickListener(this);
  276. mIvAudio.setOnClickListener(this);
  277. mIvMenu.setOnClickListener(this);
  278. mIvHorAudio.setOnClickListener(this);
  279. mIvHorTv.setOnClickListener(this);
  280. mRestartPause.setOnClickListener(this);
  281. mFullScreen.setOnClickListener(this);
  282. mClarity.setOnClickListener(this);
  283. mRetry.setOnClickListener(this);
  284. mReplay.setOnClickListener(this);
  285. mShare.setOnClickListener(this);
  286. mFlLock.setOnClickListener(this);
  287. mSeek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
  288. @Override
  289. public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
  290. }
  291. @Override
  292. public void onStartTrackingTouch(SeekBar seekBar) {
  293. }
  294. @Override
  295. public void onStopTrackingTouch(SeekBar seekBar) {
  296. if (mVideoPlayer.isBufferingPaused() || mVideoPlayer.isPaused()) {
  297. mVideoPlayer.restart();
  298. }
  299. long position = (long) (mVideoPlayer.getDuration() * seekBar.getProgress() / 100f);
  300. mVideoPlayer.seekTo(position);
  301. startDismissTopBottomTimer();
  302. }
  303. });
  304. this.setOnClickListener(this);
  305. }
  306. /**
  307. * 设置视频播放器中间的播放键是否显示,设置自定义图片
  308. * @param isVisibility 是否可见
  309. * @param image image
  310. */
  311. @Override
  312. public void setCenterPlayer(boolean isVisibility, @DrawableRes int image) {
  313. this.mIsCenterPlayerVisibility = isVisibility;
  314. if(isVisibility){
  315. if(image==0){
  316. mCenterStart.setImageResource(R.drawable.ic_player_center_start);
  317. }else {
  318. mCenterStart.setImageResource(image);
  319. }
  320. }
  321. }
  322. /**
  323. * 18年3月15日添加
  324. * 设置是否显示视频头部的下载,分享布局控件
  325. * @param isVisibility 是否可见
  326. */
  327. @Override
  328. public void setTopVisibility(boolean isVisibility) {
  329. this.mIsTopAndBottomVisibility = isVisibility;
  330. if(isVisibility){
  331. mLlTopOther.setVisibility(VISIBLE);
  332. }else {
  333. mLlTopOther.setVisibility(GONE);
  334. }
  335. }
  336. /**
  337. * 18年1月12号添加
  338. * 设置加载loading类型
  339. *
  340. * @param type 加载loading的类型
  341. * 目前1,是仿腾讯加载loading
  342. * 2,是转圈加载loading
  343. * 默认是2,后期想让用户自定义loading加载视图,不过暂时没实现
  344. * 更多可以关注我的GitHub:https://github.com/yangchong211
  345. */
  346. @Override
  347. public void setLoadingType(@ConstantKeys.LoadingType int type) {
  348. switch (type){
  349. case ConstantKeys.Loading.LOADING_RING:
  350. pbLoadingRing.setVisibility(VISIBLE);
  351. pbLoadingQq.setVisibility(GONE);
  352. break;
  353. case ConstantKeys.Loading.LOADING_QQ:
  354. pbLoadingRing.setVisibility(GONE);
  355. pbLoadingQq.setVisibility(VISIBLE);
  356. break;
  357. default:
  358. pbLoadingRing.setVisibility(VISIBLE);
  359. pbLoadingQq.setVisibility(GONE);
  360. break;
  361. }
  362. }
  363. /**
  364. * 设置不操作后,多久自动隐藏头部和底部布局
  365. * @param time 时间
  366. */
  367. @Override
  368. public void setHideTime(long time) {
  369. this.time = time;
  370. }
  371. /**
  372. * 设置视频标题
  373. * @param title 视频标题
  374. */
  375. @Override
  376. public void setTitle(String title) {
  377. mTitle.setText(title);
  378. }
  379. /**
  380. * 获取ImageView的对象
  381. * @return 对象
  382. */
  383. @Override
  384. public ImageView imageView() {
  385. return mImage;
  386. }
  387. /**
  388. * 设置图片
  389. * @param resId 视频底图资源
  390. */
  391. @Override
  392. public void setImage(@DrawableRes int resId) {
  393. mImage.setImageResource(resId);
  394. }
  395. /**
  396. * 设置视频时长
  397. * @param length 时长,long类型
  398. */
  399. @Override
  400. public void setLength(long length) {
  401. mLength.setText(VideoPlayerUtils.formatTime(length));
  402. }
  403. /**
  404. * 设置视频时长
  405. * @param length 时长,String类型
  406. */
  407. @Override
  408. public void setLength(String length) {
  409. mLength.setText(length);
  410. }
  411. /**
  412. * 设置播放器
  413. * @param VideoPlayer 播放器
  414. */
  415. @Override
  416. public void setVideoPlayer(InterVideoPlayer VideoPlayer) {
  417. super.setVideoPlayer(VideoPlayer);
  418. // 给播放器配置视频链接地址
  419. if (clarities != null && clarities.size() > 1) {
  420. mVideoPlayer.setUp(clarities.get(defaultClarityIndex).getVideoUrl(), null);
  421. }
  422. }
  423. /**
  424. * 获取是否是锁屏模式
  425. * @return true表示锁屏
  426. */
  427. @Override
  428. public boolean getLock() {
  429. return mIsLock;
  430. }
  431. /**
  432. * 如果锁屏,则屏蔽滑动事件
  433. */
  434. @Override
  435. public boolean onTouchEvent(MotionEvent event) {
  436. VideoLogUtil.i("如果锁屏2,则屏蔽返回键");
  437. //如果锁屏了,那就就不需要处理滑动的逻辑
  438. return !getLock() && super.onTouchEvent(event);
  439. }
  440. /**
  441. * 设置视频清晰度
  442. * @param clarities 清晰度
  443. * @param defaultClarityIndex 默认清晰度
  444. */
  445. public void setClarity(final List<VideoClarity> clarities, int defaultClarityIndex) {
  446. if (clarities != null && clarities.size() > 1) {
  447. this.clarities = clarities;
  448. this.defaultClarityIndex = defaultClarityIndex;
  449. List<String> clarityGrades = new ArrayList<>();
  450. for (VideoClarity clarity : clarities) {
  451. clarityGrades.add(clarity.getGrade() + " " + clarity.getP());
  452. }
  453. mClarity.setText(clarities.get(defaultClarityIndex).getGrade());
  454. // 初始化切换清晰度对话框
  455. mClarityDialog = new ChangeClarityDialog(mContext);
  456. mClarityDialog.setClarityGrade(clarityGrades, defaultClarityIndex);
  457. mClarityDialog.setOnClarityCheckedListener(new OnClarityChangedListener() {
  458. @Override
  459. public void onClarityChanged(int clarityIndex) {
  460. // 根据切换后的清晰度索引值,设置对应的视频链接地址,并从当前播放位置接着播放
  461. VideoClarity clarity = clarities.get(clarityIndex);
  462. mClarity.setText(clarity.getGrade());
  463. long currentPosition = mVideoPlayer.getCurrentPosition();
  464. //释放播放器
  465. mVideoPlayer.releasePlayer();
  466. //设置视频Url,以及headers
  467. mVideoPlayer.setUp(clarity.getVideoUrl(), null);
  468. //开始从此位置播放
  469. mVideoPlayer.start(currentPosition);
  470. }
  471. @Override
  472. public void onClarityNotChanged() {
  473. // 清晰度没有变化,对话框消失后,需要重新显示出top、bottom
  474. setTopBottomVisible(true);
  475. }
  476. });
  477. // 给播放器配置视频链接地址
  478. if (mVideoPlayer != null) {
  479. mVideoPlayer.setUp(clarities.get(defaultClarityIndex).getVideoUrl(), null);
  480. }
  481. }
  482. }
  483. /**
  484. * 当播放状态发生改变时
  485. * @param playState 播放状态:
  486. */
  487. @Override
  488. public void onPlayStateChanged(int playState) {
  489. switch (playState) {
  490. case ConstantKeys.CurrentState.STATE_IDLE:
  491. break;
  492. //播放准备中
  493. case ConstantKeys.CurrentState.STATE_PREPARING:
  494. mImage.setVisibility(View.GONE);
  495. mLoading.setVisibility(View.VISIBLE);
  496. mLoadText.setText("正在准备...");
  497. mError.setVisibility(View.GONE);
  498. mCompleted.setVisibility(View.GONE);
  499. mTop.setVisibility(View.GONE);
  500. mBottom.setVisibility(View.GONE);
  501. mCenterStart.setVisibility(View.GONE);
  502. mLength.setVisibility(View.GONE);
  503. break;
  504. //播放准备就绪
  505. case ConstantKeys.CurrentState.STATE_PREPARED:
  506. startUpdateProgressTimer();
  507. break;
  508. //正在播放
  509. case ConstantKeys.CurrentState.STATE_PLAYING:
  510. mLoading.setVisibility(View.GONE);
  511. mCenterStart.setVisibility(View.GONE);
  512. mRestartPause.setImageResource(R.drawable.ic_player_pause);
  513. startDismissTopBottomTimer();
  514. break;
  515. //暂停播放
  516. case ConstantKeys.CurrentState.STATE_PAUSED:
  517. mLoading.setVisibility(View.GONE);
  518. mCenterStart.setVisibility(mIsCenterPlayerVisibility?View.VISIBLE:View.GONE);
  519. mRestartPause.setImageResource(R.drawable.ic_player_start);
  520. cancelDismissTopBottomTimer();
  521. break;
  522. //正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,缓冲区数据足够后恢复播放)
  523. case ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING:
  524. mLoading.setVisibility(View.VISIBLE);
  525. mCenterStart.setVisibility(View.GONE);
  526. mRestartPause.setImageResource(R.drawable.ic_player_pause);
  527. mLoadText.setText("正在缓冲...");
  528. startDismissTopBottomTimer();
  529. break;
  530. //正在缓冲
  531. case ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED:
  532. mLoading.setVisibility(View.VISIBLE);
  533. mRestartPause.setImageResource(R.drawable.ic_player_start);
  534. mLoadText.setText("正在缓冲...");
  535. cancelDismissTopBottomTimer();
  536. break;
  537. //播放错误
  538. case ConstantKeys.CurrentState.STATE_ERROR:
  539. cancelUpdateProgressTimer();
  540. setTopBottomVisible(false);
  541. mTop.setVisibility(View.VISIBLE);
  542. mError.setVisibility(View.VISIBLE);
  543. break;
  544. //播放完成
  545. case ConstantKeys.CurrentState.STATE_COMPLETED:
  546. cancelUpdateProgressTimer();
  547. setTopBottomVisible(false);
  548. mImage.setVisibility(View.VISIBLE);
  549. mCompleted.setVisibility(View.VISIBLE);
  550. //设置播放完成的监听事件
  551. if(mOnCompletedListener!=null){
  552. mOnCompletedListener.onCompleted();
  553. }
  554. //当播放完成就解除广播
  555. unRegisterNetChangedReceiver();
  556. break;
  557. default:
  558. break;
  559. }
  560. }
  561. /**
  562. * 当播放器的播放模式发生变化时
  563. * @param playMode 播放器的模式:
  564. */
  565. @Override
  566. public void onPlayModeChanged(int playMode) {
  567. switch (playMode) {
  568. //普通模式
  569. case ConstantKeys.PlayMode.MODE_NORMAL:
  570. mFlLock.setVisibility(View.GONE);
  571. mBack.setVisibility(View.VISIBLE);
  572. mFullScreen.setImageResource(R.drawable.ic_player_enlarge);
  573. mFullScreen.setVisibility(View.VISIBLE);
  574. mClarity.setVisibility(View.GONE);
  575. setTopVisibility(mIsTopAndBottomVisibility);
  576. mLlHorizontal.setVisibility(View.GONE);
  577. if (hasRegisterBatteryReceiver) {
  578. mContext.unregisterReceiver(mBatterReceiver);
  579. hasRegisterBatteryReceiver = false;
  580. }
  581. mIsLock = false;
  582. break;
  583. //全屏模式
  584. case ConstantKeys.PlayMode.MODE_FULL_SCREEN:
  585. mFlLock.setVisibility(View.VISIBLE);
  586. mBack.setVisibility(View.VISIBLE);
  587. mFullScreen.setVisibility(View.GONE);
  588. mFullScreen.setImageResource(R.drawable.ic_player_shrink);
  589. if (clarities != null && clarities.size() > 1) {
  590. mClarity.setVisibility(View.VISIBLE);
  591. }
  592. mLlTopOther.setVisibility(GONE);
  593. if (mIsTopAndBottomVisibility){
  594. mLlHorizontal.setVisibility(View.VISIBLE);
  595. }else {
  596. mLlHorizontal.setVisibility(View.GONE);
  597. }
  598. if (!hasRegisterBatteryReceiver) {
  599. mContext.registerReceiver(mBatterReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  600. hasRegisterBatteryReceiver = true;
  601. }
  602. break;
  603. //小窗口模式
  604. case ConstantKeys.PlayMode.MODE_TINY_WINDOW:
  605. mFlLock.setVisibility(View.GONE);
  606. mBack.setVisibility(View.VISIBLE);
  607. mClarity.setVisibility(View.GONE);
  608. mIsLock = false;
  609. break;
  610. default:
  611. break;
  612. }
  613. }
  614. /**
  615. * 重新设置
  616. */
  617. @Override
  618. public void reset() {
  619. topBottomVisible = false;
  620. cancelUpdateProgressTimer();
  621. cancelDismissTopBottomTimer();
  622. mSeek.setProgress(0);
  623. mSeek.setSecondaryProgress(0);
  624. mCenterStart.setVisibility(VISIBLE);
  625. mLength.setVisibility(View.VISIBLE);
  626. mFlLock.setVisibility(View.GONE);
  627. mImage.setVisibility(View.VISIBLE);
  628. mBottom.setVisibility(View.GONE);
  629. mFullScreen.setImageResource(R.drawable.ic_player_enlarge);
  630. mTop.setVisibility(View.VISIBLE);
  631. mBack.setVisibility(View.VISIBLE);
  632. mLoading.setVisibility(View.GONE);
  633. mError.setVisibility(View.GONE);
  634. mCompleted.setVisibility(View.GONE);
  635. }
  636. /**
  637. * 尽量不要在onClick中直接处理控件的隐藏、显示及各种UI逻辑。
  638. * UI相关的逻辑都尽量到{@link #onPlayStateChanged}和{@link #onPlayModeChanged}中处理.
  639. */
  640. @Override
  641. public void onClick(View v) {
  642. if (v == mCenterStart) {
  643. //开始播放
  644. if (mVideoPlayer.isIdle()) {
  645. mVideoPlayer.start();
  646. }else if (mVideoPlayer.isPlaying() || mVideoPlayer.isBufferingPlaying()) {
  647. mVideoPlayer.pause();
  648. } else if (mVideoPlayer.isPaused() || mVideoPlayer.isBufferingPaused()) {
  649. mVideoPlayer.restart();
  650. }
  651. } else if (v == mBack) {
  652. //退出,执行返回逻辑
  653. //如果是全屏,则先退出全屏
  654. if (mVideoPlayer.isFullScreen()) {
  655. mVideoPlayer.exitFullScreen();
  656. } else if (mVideoPlayer.isTinyWindow()) {
  657. //如果是小窗口,则退出小窗口
  658. mVideoPlayer.exitTinyWindow();
  659. }else {
  660. //如果两种情况都不是,执行逻辑交给使用者自己实现
  661. if(mBackListener!=null){
  662. mBackListener.onBackClick();
  663. }else {
  664. VideoLogUtil.d("返回键逻辑,如果是全屏,则先退出全屏;如果是小窗口,则退出小窗口;如果两种情况都不是,执行逻辑交给使用者自己实现");
  665. }
  666. }
  667. } else if (v == mRestartPause) {
  668. if(VideoPlayerUtils.isConnected(mContext)){
  669. //重新播放或者暂停
  670. if (mVideoPlayer.isPlaying() || mVideoPlayer.isBufferingPlaying()) {
  671. mVideoPlayer.pause();
  672. if(mOnPlayOrPauseListener!=null){
  673. mOnPlayOrPauseListener.onPlayOrPauseClick(true);
  674. }
  675. } else if (mVideoPlayer.isPaused() || mVideoPlayer.isBufferingPaused()) {
  676. mVideoPlayer.restart();
  677. if(mOnPlayOrPauseListener!=null){
  678. mOnPlayOrPauseListener.onPlayOrPauseClick(false);
  679. }
  680. }
  681. }else {
  682. Toast.makeText(mContext,"请检测是否有网络",Toast.LENGTH_SHORT).show();
  683. }
  684. } else if (v == mFullScreen) {
  685. //全屏模式,重置锁屏,设置为未选中状态
  686. if (mVideoPlayer.isNormal() || mVideoPlayer.isTinyWindow()) {
  687. mFlLock.setVisibility(VISIBLE);
  688. mIsLock = false;
  689. mIvLock.setImageResource(R.drawable.player_unlock_btn);
  690. mVideoPlayer.enterFullScreen();
  691. } else if (mVideoPlayer.isFullScreen()) {
  692. mFlLock.setVisibility(GONE);
  693. mVideoPlayer.exitFullScreen();
  694. }
  695. } else if (v == mClarity) {
  696. //设置清晰度
  697. //隐藏top、bottom
  698. setTopBottomVisible(false);
  699. //显示清晰度对话框
  700. mClarityDialog.show();
  701. } else if (v == mRetry) {
  702. //点击重试
  703. //不论是否记录播放位置,都是从零开始播放
  704. if(VideoPlayerUtils.isConnected(mContext)){
  705. mVideoPlayer.restart();
  706. }else {
  707. Toast.makeText(mContext,"请检测是否有网络",Toast.LENGTH_SHORT).show();
  708. }
  709. } else if (v == mReplay) {
  710. //重新播放
  711. if(VideoPlayerUtils.isConnected(mContext)){
  712. mRetry.performClick();
  713. }else {
  714. Toast.makeText(mContext,"请检测是否有网络",Toast.LENGTH_SHORT).show();
  715. }
  716. } else if (v == mShare) {
  717. //分享
  718. Toast.makeText(mContext, "分享", Toast.LENGTH_SHORT).show();
  719. } else if(v == mFlLock){
  720. //点击锁屏按钮,则进入锁屏模式
  721. setLock(mIsLock);
  722. } else if(v == mIvDownload){
  723. if(mVideoControlListener==null){
  724. VideoLogUtil.d("请在初始化的时候设置下载监听事件");
  725. return;
  726. }
  727. //点击下载
  728. mVideoControlListener.onVideoControlClick(ConstantKeys.VideoControl.DOWNLOAD);
  729. } else if(v == mIvAudio){
  730. if(mVideoControlListener==null){
  731. VideoLogUtil.d("请在初始化的时候设置切换监听事件");
  732. return;
  733. }
  734. //点击切换音频
  735. mVideoControlListener.onVideoControlClick(ConstantKeys.VideoControl.AUDIO);
  736. }else if(v == mIvShare){
  737. if(mVideoControlListener==null){
  738. VideoLogUtil.d("请在初始化的时候设置分享监听事件");
  739. return;
  740. }
  741. //点击分享
  742. mVideoControlListener.onVideoControlClick(ConstantKeys.VideoControl.SHARE);
  743. }else if(v == mIvMenu){
  744. if(mVideoControlListener==null){
  745. VideoLogUtil.d("请在初始化的时候设置分享监听事件");
  746. return;
  747. }
  748. //点击菜单
  749. mVideoControlListener.onVideoControlClick(ConstantKeys.VideoControl.MENU);
  750. }else if(v == mIvHorAudio){
  751. if(mVideoControlListener==null){
  752. VideoLogUtil.d("请在初始化的时候设置横向音频监听事件");
  753. return;
  754. }
  755. //点击横向音频
  756. mVideoControlListener.onVideoControlClick(ConstantKeys.VideoControl.HOR_AUDIO);
  757. }else if(v == mIvHorTv){
  758. if(mVideoControlListener==null){
  759. VideoLogUtil.d("请在初始化的时候设置横向Tv监听事件");
  760. return;
  761. }
  762. //点击横向TV
  763. mVideoControlListener.onVideoControlClick(ConstantKeys.VideoControl.TV);
  764. } else if (v == this) {
  765. if (mVideoPlayer.isPlaying() || mVideoPlayer.isPaused()
  766. || mVideoPlayer.isBufferingPlaying() || mVideoPlayer.isBufferingPaused()) {
  767. setTopBottomVisible(!topBottomVisible);
  768. }
  769. }
  770. }
  771. /**
  772. * 设置top、bottom的显示和隐藏
  773. * @param visible true显示,false隐藏.
  774. */
  775. private void setTopBottomVisible(boolean visible) {
  776. mTop.setVisibility(visible ? View.VISIBLE : View.GONE);
  777. mBottom.setVisibility(visible ? View.VISIBLE : View.GONE);
  778. topBottomVisible = visible;
  779. if (visible) {
  780. if (!mVideoPlayer.isPaused() && !mVideoPlayer.isBufferingPaused()) {
  781. startDismissTopBottomTimer();
  782. }
  783. } else {
  784. cancelDismissTopBottomTimer();
  785. }
  786. }
  787. /**
  788. * 开启top、bottom自动消失的timer
  789. * 比如,视频常用功能,当用户5秒不操作后,自动隐藏头部和顶部
  790. */
  791. private void startDismissTopBottomTimer() {
  792. if(time==0){
  793. time = 8000;
  794. }
  795. cancelDismissTopBottomTimer();
  796. if (mDismissTopBottomCountDownTimer == null) {
  797. mDismissTopBottomCountDownTimer = new CountDownTimer(time, time) {
  798. @Override
  799. public void onTick(long millisUntilFinished) {
  800. }
  801. @Override
  802. public void onFinish() {
  803. setTopBottomVisible(false);
  804. }
  805. };
  806. }
  807. mDismissTopBottomCountDownTimer.start();
  808. }
  809. /**
  810. * 取消top、bottom自动消失的timer
  811. */
  812. private void cancelDismissTopBottomTimer() {
  813. if (mDismissTopBottomCountDownTimer != null) {
  814. mDismissTopBottomCountDownTimer.cancel();
  815. }
  816. }
  817. /**
  818. * 设置锁屏模式,默认是未锁屏的
  819. * 当为true时,则锁屏;否则为未锁屏
  820. * @param isLock 是否锁屏
  821. */
  822. private void setLock(boolean isLock){
  823. if(isLock){
  824. mIsLock = false;
  825. mIvLock.setImageResource(R.drawable.player_unlock_btn);
  826. }else {
  827. mIsLock = true;
  828. mIvLock.setImageResource(R.drawable.player_locked_btn);
  829. }
  830. /*
  831. * 设置锁屏时的布局
  832. * 1.横屏全屏时显示,其他不展示;
  833. * 2.锁屏时隐藏控制面板除锁屏按钮外其他所有控件
  834. * 3.当从全屏切换到正常或者小窗口时,则默认不锁屏
  835. */
  836. setTopBottomVisible(!mIsLock);
  837. }
  838. /**
  839. * 更新播放进度
  840. */
  841. @Override
  842. protected void updateProgress() {
  843. //获取当前播放的位置,毫秒
  844. long position = mVideoPlayer.getCurrentPosition();
  845. //获取办法给总时长,毫秒
  846. long duration = mVideoPlayer.getDuration();
  847. //获取视频缓冲百分比
  848. int bufferPercentage = mVideoPlayer.getBufferPercentage();
  849. mSeek.setSecondaryProgress(bufferPercentage);
  850. int progress = (int) (100f * position / duration);
  851. mSeek.setProgress(progress);
  852. mPosition.setText(VideoPlayerUtils.formatTime(position));
  853. mDuration.setText(VideoPlayerUtils.formatTime(duration));
  854. // 更新时间
  855. mTime.setText(new SimpleDateFormat("HH:mm", Locale.CHINA).format(new Date()));
  856. }
  857. /**
  858. * 显示视频播放位置
  859. * @param duration 视频总时长ms
  860. * @param newPositionProgress 新的位置进度,取值0到100。
  861. */
  862. @Override
  863. protected void showChangePosition(long duration, int newPositionProgress) {
  864. mChangePosition.setVisibility(View.VISIBLE);
  865. long newPosition = (long) (duration * newPositionProgress / 100f);
  866. mChangePositionCurrent.setText(VideoPlayerUtils.formatTime(newPosition));
  867. mChangePositionProgress.setProgress(newPositionProgress);
  868. mSeek.setProgress(newPositionProgress);
  869. mPosition.setText(VideoPlayerUtils.formatTime(newPosition));
  870. }
  871. /**
  872. * 隐藏视频播放位置
  873. */
  874. @Override
  875. protected void hideChangePosition() {
  876. mChangePosition.setVisibility(View.GONE);
  877. }
  878. /**
  879. * 展示视频播放音量
  880. * @param newVolumeProgress 新的音量进度,取值1到100。
  881. */
  882. @Override
  883. protected void showChangeVolume(int newVolumeProgress) {
  884. mChangeVolume.setVisibility(View.VISIBLE);
  885. mChangeVolumeProgress.setProgress(newVolumeProgress);
  886. }
  887. /**
  888. * 隐藏视频播放音量
  889. */
  890. @Override
  891. protected void hideChangeVolume() {
  892. mChangeVolume.setVisibility(View.GONE);
  893. }
  894. /**
  895. * 展示视频播放亮度
  896. * @param newBrightnessProgress 新的亮度进度,取值1到100。
  897. */
  898. @Override
  899. protected void showChangeBrightness(int newBrightnessProgress) {
  900. mChangeBrightness.setVisibility(View.VISIBLE);
  901. mChangeBrightnessProgress.setProgress(newBrightnessProgress);
  902. }
  903. /**
  904. * 隐藏视频播放亮度
  905. */
  906. @Override
  907. protected void hideChangeBrightness() {
  908. mChangeBrightness.setVisibility(View.GONE);
  909. }
  910. /**
  911. * 当视频退出全屏或者退出小窗口后,再次点击返回键
  912. * 让用户自己处理返回键事件的逻辑
  913. * 欢迎同行交流:https://github.com/yangchong211
  914. * 如果你觉得项目可以,欢迎star
  915. */
  916. private OnVideoBackListener mBackListener;
  917. public void setOnVideoBackListener(OnVideoBackListener listener) {
  918. this.mBackListener = listener;
  919. }
  920. /**
  921. * 设置视频分享,下载,音视频转化点击事件
  922. */
  923. private OnVideoControlListener mVideoControlListener;
  924. public void setOnVideoControlListener(OnVideoControlListener listener){
  925. this.mVideoControlListener = listener;
  926. }
  927. /**
  928. * 播放暂停监听事件
  929. */
  930. private OnPlayOrPauseListener mOnPlayOrPauseListener;
  931. public void setOnPlayOrPauseListener(OnPlayOrPauseListener listener){
  932. this.mOnPlayOrPauseListener = listener;
  933. }
  934. /**
  935. * 监听视频播放完成事件
  936. */
  937. private OnCompletedListener mOnCompletedListener;
  938. public void setOnCompletedListener(OnCompletedListener listener){
  939. this.mOnCompletedListener = listener;
  940. }
  941. }