package fm.jiecao.jcvideoplayer_lib; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.SurfaceTexture; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.media.AudioManager; import android.os.Handler; import android.support.v7.app.ActionBar; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.Window; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import tv.danmaku.ijk.media.player.IMediaPlayer; /** * Created by Nathen on 16/7/30. */ public abstract class JCVideoPlayer extends FrameLayout implements JCMediaPlayerListener, View.OnClickListener, SeekBar.OnSeekBarChangeListener, View.OnTouchListener, TextureView.SurfaceTextureListener { public static final String TAG = "JieCaoVideoPlayer"; public static final int FULLSCREEN_ID = 33797; public static final int TINY_ID = 33798; public static final int THRESHOLD = 80; public static final int FULL_SCREEN_NORMAL_DELAY = 500; public static boolean ACTION_BAR_EXIST = true; public static boolean TOOL_BAR_EXIST = true; public static boolean WIFI_TIP_DIALOG_SHOWED = false; public static int FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_SENSOR; public static int NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; public static long CLICK_QUIT_FULLSCREEN_TIME = 0; public static final int SCREEN_LAYOUT_NORMAL = 0; public static final int SCREEN_LAYOUT_LIST = 1; public static final int SCREEN_WINDOW_FULLSCREEN = 2; public static final int SCREEN_WINDOW_TINY = 3; public static final int CURRENT_STATE_NORMAL = 0; public static final int CURRENT_STATE_PREPARING = 1; public static final int CURRENT_STATE_PLAYING = 2; public static final int CURRENT_STATE_PLAYING_BUFFERING_START = 3; public static final int CURRENT_STATE_PAUSE = 5; public static final int CURRENT_STATE_AUTO_COMPLETE = 6; public static final int CURRENT_STATE_ERROR = 7; public int currentState = -1; public int currentScreen = -1; public String url = ""; public Object[] objects = null; public boolean looping = false; public Map<String, String> mapHeadData = new HashMap<>(); public int seekToInAdvance = -1; protected static Bitmap pauseSwitchCoverBitmap = null; private boolean textureUpdated; private boolean textureSizeChanged; public ImageView startButton; public JCResizeImageView cacheImageView; public SeekBar progressBar; public ImageView fullscreenButton; public TextView currentTimeTextView, totalTimeTextView; public ViewGroup textureViewContainer; public ViewGroup topContainer, bottomContainer; public Surface surface; protected static WeakReference<JCUserAction> JC_USER_EVENT; protected static Timer UPDATE_PROGRESS_TIMER; protected int mScreenWidth; protected int mScreenHeight; protected AudioManager mAudioManager; protected Handler mHandler; protected ProgressTimerTask mProgressTimerTask; protected boolean mTouchingProgressBar; protected float mDownX; protected float mDownY; protected boolean mChangeVolume; protected boolean mChangePosition; protected int mDownPosition; protected int mGestureDownVolume; protected int mSeekTimePosition; public JCVideoPlayer(Context context) { super(context); init(context); } public JCVideoPlayer(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public void init(Context context) { View.inflate(context, getLayoutId(), this); startButton = (ImageView) findViewById(R.id.start); fullscreenButton = (ImageView) findViewById(R.id.fullscreen); progressBar = (SeekBar) findViewById(R.id.progress); currentTimeTextView = (TextView) findViewById(R.id.current); totalTimeTextView = (TextView) findViewById(R.id.total); bottomContainer = (ViewGroup) findViewById(R.id.layout_bottom); textureViewContainer = (ViewGroup) findViewById(R.id.surface_container); topContainer = (ViewGroup) findViewById(R.id.layout_top); cacheImageView = (JCResizeImageView) findViewById(R.id.cache); startButton.setOnClickListener(this); fullscreenButton.setOnClickListener(this); progressBar.setOnSeekBarChangeListener(this); bottomContainer.setOnClickListener(this); textureViewContainer.setOnClickListener(this); textureViewContainer.setOnTouchListener(this); mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels; mScreenHeight = getContext().getResources().getDisplayMetrics().heightPixels; mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mHandler = new Handler(); } public boolean setUp(String url, int screen, Object... objects) { if (!TextUtils.isEmpty(this.url) && TextUtils.equals(this.url, url)) { return false; } JCVideoPlayerManager.checkAndPutListener(this); if (JCVideoPlayerManager.CURRENT_SCROLL_LISTENER != null && JCVideoPlayerManager.CURRENT_SCROLL_LISTENER.get() != null) { if (this == JCVideoPlayerManager.CURRENT_SCROLL_LISTENER.get()) { if (((JCVideoPlayer) JCVideoPlayerManager.CURRENT_SCROLL_LISTENER.get()).currentState == CURRENT_STATE_PLAYING) { if (url.equals(JCMediaManager.instance().mediaPlayer.getDataSource())) { ((JCVideoPlayer) JCVideoPlayerManager.CURRENT_SCROLL_LISTENER.get()).startWindowTiny();//如果列表中,滑动过快,在还没来得及onScroll的时候自己已经被复用了 } } } } this.url = url; this.objects = objects; this.currentScreen = screen; setUiWitStateAndScreen(CURRENT_STATE_NORMAL); if (url.equals(JCMediaManager.instance().mediaPlayer.getDataSource())) {//如果初始化了一个正在tinyWindow的前身,就应该监听它的滑动,如果显示就在这个listener中播放 JCVideoPlayerManager.putScrollListener(this); } return true; } @Override public int getScreenType() { return currentScreen; } @Override public String getUrl() { return url; } @Override public int getState() { return currentState; } public boolean setUp(String url, int screen, Map<String, String> mapHeadData, Object... objects) { if (setUp(url, screen, objects)) { this.mapHeadData.clear(); this.mapHeadData.putAll(mapHeadData); return true; } return false; } @Override public void onClick(View v) { int i = v.getId(); if (i == R.id.start) { Log.i(TAG, "onClick start [" + this.hashCode() + "] "); if (TextUtils.isEmpty(url)) { Toast.makeText(getContext(), getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show(); return; } if (currentState == CURRENT_STATE_NORMAL || currentState == CURRENT_STATE_ERROR) { if (!url.startsWith("file") && !JCUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) { showWifiDialog(); return; } prepareVideo(); onEvent(currentState != CURRENT_STATE_ERROR ? JCUserAction.ON_CLICK_START_ICON : JCUserAction.ON_CLICK_START_ERROR); } else if (currentState == CURRENT_STATE_PLAYING) { obtainCache(); onEvent(JCUserAction.ON_CLICK_PAUSE); Log.d(TAG, "pauseVideo [" + this.hashCode() + "] "); JCMediaManager.instance().mediaPlayer.pause(); setUiWitStateAndScreen(CURRENT_STATE_PAUSE); refreshCache(); } else if (currentState == CURRENT_STATE_PAUSE) { onEvent(JCUserAction.ON_CLICK_RESUME); JCMediaManager.instance().mediaPlayer.start(); setUiWitStateAndScreen(CURRENT_STATE_PLAYING); } else if (currentState == CURRENT_STATE_AUTO_COMPLETE) { onEvent(JCUserAction.ON_CLICK_START_AUTO_COMPLETE); prepareVideo(); } } else if (i == R.id.fullscreen) { Log.i(TAG, "onClick fullscreen [" + this.hashCode() + "] "); if (currentState == CURRENT_STATE_AUTO_COMPLETE) return; if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { //quit fullscreen backPress(); } else { Log.d(TAG, "toFullscreenActivity [" + this.hashCode() + "] "); onEvent(JCUserAction.ON_ENTER_FULLSCREEN); startWindowFullscreen(); } } else if (i == R.id.surface_container && currentState == CURRENT_STATE_ERROR) { Log.i(TAG, "onClick surfaceContainer State=Error [" + this.hashCode() + "] "); prepareVideo(); } } public void prepareVideo() { Log.d(TAG, "prepareVideo [" + this.hashCode() + "] "); JCVideoPlayerManager.completeAll(); JCVideoPlayerManager.putListener(this); addTextureView(); AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); JCUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); JCVideoPlayerManager.putScrollListener(this); JCMediaManager.instance().prepare(url, mapHeadData, looping); setUiWitStateAndScreen(CURRENT_STATE_PREPARING); } @Override public boolean onTouch(View v, MotionEvent event) { float x = event.getX(); float y = event.getY(); int id = v.getId(); if (id == R.id.surface_container) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.i(TAG, "onTouch surfaceContainer actionDown [" + this.hashCode() + "] "); mTouchingProgressBar = true; mDownX = x; mDownY = y; mChangeVolume = false; mChangePosition = false; ///////////////////// break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "onTouch surfaceContainer actionMove [" + this.hashCode() + "] "); float deltaX = x - mDownX; float deltaY = y - mDownY; float absDeltaX = Math.abs(deltaX); float absDeltaY = Math.abs(deltaY); if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { if (!mChangePosition && !mChangeVolume) { if (absDeltaX > THRESHOLD || absDeltaY > THRESHOLD) { cancelProgressTimer(); if (absDeltaX >= THRESHOLD) { // 全屏模式下的CURRENT_STATE_ERROR状态下,不响应进度拖动事件. // 否则会因为mediaplayer的状态非法导致App Crash if (currentState != CURRENT_STATE_ERROR) { mChangePosition = true; mDownPosition = getCurrentPositionWhenPlaying(); } } else { mChangeVolume = true; mGestureDownVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); } } } } if (mChangePosition) { int totalTimeDuration = getDuration(); mSeekTimePosition = (int) (mDownPosition + deltaX * totalTimeDuration / mScreenWidth); if (mSeekTimePosition > totalTimeDuration) mSeekTimePosition = totalTimeDuration; String seekTime = JCUtils.stringForTime(mSeekTimePosition); String totalTime = JCUtils.stringForTime(totalTimeDuration); showProgressDialog(deltaX, seekTime, mSeekTimePosition, totalTime, totalTimeDuration); } if (mChangeVolume) { deltaY = -deltaY; int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int deltaV = (int) (max * deltaY * 3 / mScreenHeight); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mGestureDownVolume + deltaV, 0); int volumePercent = (int) (mGestureDownVolume * 100 / max + deltaY * 3 * 100 / mScreenHeight); showVolumeDialog(-deltaY, volumePercent); } break; case MotionEvent.ACTION_UP: Log.i(TAG, "onTouch surfaceContainer actionUp [" + this.hashCode() + "] "); mTouchingProgressBar = false; dismissProgressDialog(); dismissVolumeDialog(); if (mChangePosition) { onEvent(JCUserAction.ON_TOUCH_SCREEN_SEEK_POSITION); JCMediaManager.instance().mediaPlayer.seekTo(mSeekTimePosition); int duration = getDuration(); int progress = mSeekTimePosition * 100 / (duration == 0 ? 1 : duration); progressBar.setProgress(progress); } if (mChangeVolume) { onEvent(JCUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME); } startProgressTimer(); break; } } return false; } public void addTextureView() { Log.d(TAG, "addTextureView [" + this.hashCode() + "] "); if (textureViewContainer.getChildCount() > 0) { textureViewContainer.removeAllViews(); } JCMediaManager.textureView = null; JCMediaManager.textureView = new JCResizeTextureView(getContext()); JCMediaManager.textureView.setVideoSize(JCMediaManager.instance().getVideoSize()); JCMediaManager.textureView.setRotation(JCMediaManager.instance().videoRotation); JCMediaManager.textureView.setSurfaceTextureListener(this); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); textureViewContainer.addView(JCMediaManager.textureView, layoutParams); cacheImageView.setVideoSize(JCMediaManager.instance().getVideoSize()); cacheImageView.setRotation(JCMediaManager.instance().videoRotation); } public void setUiWitStateAndScreen(int state) { currentState = state; switch (currentState) { case CURRENT_STATE_NORMAL: if (isCurrentMediaListener()) { cancelProgressTimer(); JCMediaManager.instance().releaseMediaPlayer(); } break; case CURRENT_STATE_PREPARING: resetProgressAndTime(); break; case CURRENT_STATE_PLAYING: case CURRENT_STATE_PAUSE: case CURRENT_STATE_PLAYING_BUFFERING_START: startProgressTimer(); break; case CURRENT_STATE_ERROR: cancelProgressTimer(); if (isCurrentMediaListener()) { JCMediaManager.instance().releaseMediaPlayer(); } break; case CURRENT_STATE_AUTO_COMPLETE: cancelProgressTimer(); progressBar.setProgress(100); currentTimeTextView.setText(totalTimeTextView.getText()); break; } } public void startProgressTimer() { cancelProgressTimer(); UPDATE_PROGRESS_TIMER = new Timer(); mProgressTimerTask = new ProgressTimerTask(); UPDATE_PROGRESS_TIMER.schedule(mProgressTimerTask, 0, 300); } public void cancelProgressTimer() { if (UPDATE_PROGRESS_TIMER != null) { UPDATE_PROGRESS_TIMER.cancel(); } if (mProgressTimerTask != null) { mProgressTimerTask.cancel(); } } @Override public void onPrepared() { Log.i(TAG, "onPrepared " + " [" + this.hashCode() + "] "); if (currentState != CURRENT_STATE_PREPARING) return; JCMediaManager.instance().mediaPlayer.start(); if (seekToInAdvance != -1) { JCMediaManager.instance().mediaPlayer.seekTo(seekToInAdvance); seekToInAdvance = -1; } startProgressTimer(); setUiWitStateAndScreen(CURRENT_STATE_PLAYING); } public void clearFullscreenLayout() { ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View oldF = vp.findViewById(FULLSCREEN_ID); View oldT = vp.findViewById(TINY_ID); if (oldF != null) { vp.removeView(oldF); } if (oldT != null) { vp.removeView(oldT); } showSupportActionBar(getContext()); } @Override public void onAutoCompletion() { Log.i(TAG, "onAutoCompletion " + " [" + this.hashCode() + "] "); onEvent(JCUserAction.ON_AUTO_COMPLETE); dismissVolumeDialog(); dismissProgressDialog(); setUiWitStateAndScreen(CURRENT_STATE_AUTO_COMPLETE); JCVideoPlayerManager.popListener();//自己进入autoComplete状态,其他的进入complete状态 JCVideoPlayerManager.completeAll(); } @Override public void onCompletion() { Log.i(TAG, "onCompletion " + " [" + this.hashCode() + "] "); setUiWitStateAndScreen(CURRENT_STATE_NORMAL); if (textureViewContainer.getChildCount() > 0) { textureViewContainer.removeAllViews(); } JCMediaManager.instance().currentVideoWidth = 0; JCMediaManager.instance().currentVideoHeight = 0; // 清理缓存变量 JCMediaManager.instance().bufferPercent = 0; JCMediaManager.instance().videoRotation = 0; AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager.abandonAudioFocus(onAudioFocusChangeListener); JCUtils.scanForActivity(getContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); clearFullscreenLayout(); JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(NORMAL_ORIENTATION); // 清理cover image,回收bitmap内存 clearCacheImage(); } @Override public boolean backToOtherListener() {//这里这个名字这么写并不对,这是在回退的时候gotoother,如果直接gotoother就不叫这个名字 obtainCache(); Log.i(TAG, "backToOtherListener " + " [" + this.hashCode() + "] "); JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(NORMAL_ORIENTATION); if (currentScreen == JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN || currentScreen == JCVideoPlayerStandard.SCREEN_WINDOW_TINY) { // if (currentScreen == JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN) { // final Animation ra = AnimationUtils.loadAnimation(getContext(), R.anim.quit_fullscreen); // startAnimation(ra); // } onEvent(currentScreen == JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN ? JCUserAction.ON_QUIT_FULLSCREEN : JCUserAction.ON_QUIT_TINYSCREEN); if (JCVideoPlayerManager.LISTENERLIST.size() == 1) {//directly fullscreen JCVideoPlayerManager.popListener().onCompletion(); JCMediaManager.instance().releaseMediaPlayer(); showSupportActionBar(getContext()); return true; } ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); vp.removeView(this); JCMediaManager.instance().lastState = currentState;//save state JCVideoPlayerManager.popListener(); if (JCVideoPlayerManager.getFirst() != null) { JCVideoPlayerManager.getFirst().goBackThisListener(); CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis(); refreshCache(); } else { JCVideoPlayerManager.completeAll(); } return true; } return false; } public static long lastAutoFullscreenTime = 0; @Override public void autoFullscreen(float x) { if (isCurrentMediaListener() && currentState == CURRENT_STATE_PLAYING && currentScreen != SCREEN_WINDOW_FULLSCREEN && currentScreen != SCREEN_WINDOW_TINY) { if (x > 0) { JCUtils.getAppCompActivity(getContext()).setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } else { JCUtils.getAppCompActivity(getContext()).setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); } startWindowFullscreen(); } } @Override public void autoQuitFullscreen() { if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000 && isCurrentMediaListener() && currentState == CURRENT_STATE_PLAYING && currentScreen == SCREEN_WINDOW_FULLSCREEN) { lastAutoFullscreenTime = System.currentTimeMillis(); backPress(); } } @Override public void goBackThisListener() { Log.i(TAG, "goBackThisListener " + " [" + this.hashCode() + "] "); currentState = JCMediaManager.instance().lastState; setUiWitStateAndScreen(currentState); addTextureView(); showSupportActionBar(getContext()); } @Override public void onBufferingUpdate(int percent) { if (currentState != CURRENT_STATE_NORMAL && currentState != CURRENT_STATE_PREPARING) { Log.v(TAG, "onBufferingUpdate " + percent + " [" + this.hashCode() + "] "); JCMediaManager.instance().bufferPercent = percent; setTextAndProgress(percent); } } @Override public void onSeekComplete() { } @Override public void onError(int what, int extra) { Log.e(TAG, "onError " + what + " - " + extra + " [" + this.hashCode() + "] "); if (what != 38 && what != -38) { setUiWitStateAndScreen(CURRENT_STATE_ERROR); } } @Override public void onInfo(int what, int extra) { Log.d(TAG, "onInfo what - " + what + " extra - " + extra); if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START) { JCMediaManager.instance().backUpBufferState = currentState; setUiWitStateAndScreen(CURRENT_STATE_PLAYING_BUFFERING_START); Log.d(TAG, "MEDIA_INFO_BUFFERING_START"); } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) { if (JCMediaManager.instance().backUpBufferState != -1) { setUiWitStateAndScreen(JCMediaManager.instance().backUpBufferState); JCMediaManager.instance().backUpBufferState = -1; } Log.d(TAG, "MEDIA_INFO_BUFFERING_END"); } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) { JCMediaManager.instance().videoRotation = extra; JCMediaManager.textureView.setRotation(extra); cacheImageView.setRotation(JCMediaManager.instance().videoRotation); Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED"); } } @Override public void onVideoSizeChanged() { Log.i(TAG, "onVideoSizeChanged " + " [" + this.hashCode() + "] "); JCMediaManager.textureView.setVideoSize(JCMediaManager.instance().getVideoSize()); cacheImageView.setVideoSize(JCMediaManager.instance().getVideoSize()); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { Log.i(TAG, "onSurfaceTextureAvailable [" + this.hashCode() + "] "); this.surface = new Surface(surface); JCMediaManager.instance().setDisplay(this.surface); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // 如果SurfaceTexture还没有更新Image,则记录SizeChanged事件,否则忽略 textureSizeChanged = true; Log.i(TAG, "onSurfaceTextureSizeChanged [" + this.hashCode() + "] "); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { surface.release(); return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { // 如果textureSizeChanged=true,则说明此次Updated事件不是Image更新引起的 应该是TextureSizeChanged引起的 所以不需要更新 cacheImageView Log.i(TAG, "onSurfaceTextureUpdated [" + this.hashCode() + "] textureSizeChanged=" + textureSizeChanged); if (!textureSizeChanged) { cacheImageView.setVisibility(INVISIBLE); JCMediaManager.textureView.setHasUpdated(); } else { textureSizeChanged = false; } } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { Log.i(TAG, "bottomProgress onStartTrackingTouch [" + this.hashCode() + "] "); cancelProgressTimer(); ViewParent vpdown = getParent(); while (vpdown != null) { vpdown.requestDisallowInterceptTouchEvent(true); vpdown = vpdown.getParent(); } } @Override public void onStopTrackingTouch(SeekBar seekBar) { Log.i(TAG, "bottomProgress onStopTrackingTouch [" + this.hashCode() + "] "); onEvent(JCUserAction.ON_SEEK_POSITION); startProgressTimer(); ViewParent vpup = getParent(); while (vpup != null) { vpup.requestDisallowInterceptTouchEvent(false); vpup = vpup.getParent(); } if (currentState != CURRENT_STATE_PLAYING && currentState != CURRENT_STATE_PAUSE) return; int time = seekBar.getProgress() * getDuration() / 100; JCMediaManager.instance().mediaPlayer.seekTo(time); Log.i(TAG, "seekTo " + time + " [" + this.hashCode() + "] "); } public static boolean backPress() { Log.i(TAG, "backPress"); if (JCVideoPlayerManager.getFirst() != null) { return JCVideoPlayerManager.getFirst().backToOtherListener(); } return false; } public void startWindowFullscreen() { obtainCache(); Log.i(TAG, "startWindowFullscreen " + " [" + this.hashCode() + "] "); CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis(); hideSupportActionBar(getContext()); JCUtils.getAppCompActivity(getContext()).setRequestedOrientation(FULLSCREEN_ORIENTATION); ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View old = vp.findViewById(FULLSCREEN_ID); if (old != null) { vp.removeView(old); } if (textureViewContainer.getChildCount() > 0) { textureViewContainer.removeAllViews(); } try { Constructor<JCVideoPlayer> constructor = (Constructor<JCVideoPlayer>) JCVideoPlayer.this.getClass().getConstructor(Context.class); JCVideoPlayer jcVideoPlayer = constructor.newInstance(getContext()); jcVideoPlayer.setId(FULLSCREEN_ID); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); vp.addView(jcVideoPlayer, lp); jcVideoPlayer.setUp(url, JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN, objects); jcVideoPlayer.setUiWitStateAndScreen(currentState); jcVideoPlayer.addTextureView(); // final Animation ra = AnimationUtils.loadAnimation(getContext(), R.anim.start_fullscreen); // jcVideoPlayer.setAnimation(ra); JCVideoPlayerManager.putListener(jcVideoPlayer); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } refreshCache(); } public void startWindowTiny() { Log.i(TAG, "startWindowTiny " + " [" + this.hashCode() + "] "); onEvent(JCUserAction.ON_ENTER_TINYSCREEN); ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View old = vp.findViewById(TINY_ID); if (old != null) { vp.removeView(old); } if (textureViewContainer.getChildCount() > 0) { textureViewContainer.removeAllViews(); } try { Constructor<JCVideoPlayer> constructor = (Constructor<JCVideoPlayer>) JCVideoPlayer.this.getClass().getConstructor(Context.class); JCVideoPlayer mJcVideoPlayer = constructor.newInstance(getContext()); mJcVideoPlayer.setId(TINY_ID); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(400, 400); lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; vp.addView(mJcVideoPlayer, lp); mJcVideoPlayer.setUp(url, JCVideoPlayerStandard.SCREEN_WINDOW_TINY, objects); mJcVideoPlayer.setUiWitStateAndScreen(currentState); mJcVideoPlayer.addTextureView(); JCVideoPlayerManager.putListener(mJcVideoPlayer); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public class ProgressTimerTask extends TimerTask { @Override public void run() { if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE || currentState == CURRENT_STATE_PLAYING_BUFFERING_START) { int position = getCurrentPositionWhenPlaying(); int duration = getDuration(); Log.v(TAG, "onProgressUpdate " + position + "/" + duration + " [" + this.hashCode() + "] "); mHandler.post(new Runnable() { @Override public void run() { setTextAndProgress(JCMediaManager.instance().bufferPercent); } }); } } } public int getCurrentPositionWhenPlaying() { int position = 0; if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE || currentState == CURRENT_STATE_PLAYING_BUFFERING_START) { try { position = (int) JCMediaManager.instance().mediaPlayer.getCurrentPosition(); } catch (IllegalStateException e) { e.printStackTrace(); return position; } } return position; } public int getDuration() { int duration = 0; try { duration = (int) JCMediaManager.instance().mediaPlayer.getDuration(); } catch (IllegalStateException e) { e.printStackTrace(); return duration; } return duration; } public void setTextAndProgress(int secProgress) { int position = getCurrentPositionWhenPlaying(); int duration = getDuration(); int progress = position * 100 / (duration == 0 ? 1 : duration); setProgressAndTime(progress, secProgress, position, duration); } public void setProgressAndTime(int progress, int secProgress, int currentTime, int totalTime) { if (!mTouchingProgressBar) { if (progress != 0) progressBar.setProgress(progress); } if (secProgress > 95) secProgress = 100; if (secProgress != 0) progressBar.setSecondaryProgress(secProgress); if (currentTime != 0) currentTimeTextView.setText(JCUtils.stringForTime(currentTime)); totalTimeTextView.setText(JCUtils.stringForTime(totalTime)); } public void resetProgressAndTime() { progressBar.setProgress(0); progressBar.setSecondaryProgress(0); currentTimeTextView.setText(JCUtils.stringForTime(0)); totalTimeTextView.setText(JCUtils.stringForTime(0)); } public static AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: break; case AudioManager.AUDIOFOCUS_LOSS: releaseAllVideos(); Log.d(TAG, "AUDIOFOCUS_LOSS [" + this.hashCode() + "]"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: if (JCMediaManager.instance().mediaPlayer.isPlaying()) { JCMediaManager.instance().mediaPlayer.pause(); } Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT [" + this.hashCode() + "]"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: break; } } }; public void release() { if (url.equals(JCMediaManager.instance().mediaPlayer.getDataSource()) && (System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) > FULL_SCREEN_NORMAL_DELAY) { //如果正在全屏播放就不能手动调用release if (JCVideoPlayerManager.getFirst() != null && JCVideoPlayerManager.getFirst().getScreenType() != SCREEN_WINDOW_FULLSCREEN) { Log.d(TAG, "release [" + this.hashCode() + "]"); releaseAllVideos(); } } } //isCurrentMediaListener and isCurrenPlayUrl should be two logic methods,isCurrentMediaListener is for different jcvd with same //url when fullscreen or tiny screen. isCurrenPlayUrl is to find where is myself when back from tiny screen. //Sometimes they are overlap. public boolean isCurrentMediaListener() { return JCVideoPlayerManager.getFirst() != null && JCVideoPlayerManager.getFirst() == this; } public boolean isCurrenPlayingUrl() { return url.equals(JCMediaManager.instance().mediaPlayer.getDataSource()); } public static void releaseAllVideos() { Log.d(TAG, "releaseAllVideos"); JCVideoPlayerManager.completeAll(); JCMediaManager.instance().releaseMediaPlayer(); } public static void setJcUserAction(JCUserAction jcUserEvent) { JC_USER_EVENT = new WeakReference<>(jcUserEvent); } public void onEvent(int type) { if (JC_USER_EVENT != null && JC_USER_EVENT.get() != null && isCurrentMediaListener()) { JC_USER_EVENT.get().onEvent(type, url, currentScreen, objects); } } @Override public void onScrollChange() {//这里需要自己判断自己是 进入小窗,退出小窗,暂停还是播放 if (url.equals(JCMediaManager.instance().mediaPlayer.getDataSource())) { if (JCVideoPlayerManager.getFirst() == null) return; if (JCVideoPlayerManager.getFirst().getScreenType() == SCREEN_WINDOW_TINY) { //如果正在播放的是小窗,择机退出小窗 if (isShown()) {//已经显示,就退出小窗 backPress(); } } else { //如果正在播放的不是小窗,择机进入小窗 if (!isShown()) {//已经隐藏 if (currentState != CURRENT_STATE_PLAYING) { releaseAllVideos(); } else { startWindowTiny(); } } } } } public static void onScroll() {//这里就应该保证,listener的正确的完整的赋值,调用非播放的控件 if (JCVideoPlayerManager.CURRENT_SCROLL_LISTENER != null && JCVideoPlayerManager.CURRENT_SCROLL_LISTENER.get() != null) { JCMediaPlayerListener jcMediaPlayerListener = JCVideoPlayerManager.CURRENT_SCROLL_LISTENER.get(); if (//jcMediaPlayerListenerWeakReference.get().getState() != CURRENT_STATE_NORMAL && jcMediaPlayerListener.getState() != CURRENT_STATE_ERROR && jcMediaPlayerListener.getState() != CURRENT_STATE_AUTO_COMPLETE) { jcMediaPlayerListener.onScrollChange(); } } } public static void startFullscreen(Context context, Class _class, String url, Object... objects) { hideSupportActionBar(context); JCUtils.getAppCompActivity(context).setRequestedOrientation(FULLSCREEN_ORIENTATION); ViewGroup vp = (ViewGroup) (JCUtils.scanForActivity(context))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View old = vp.findViewById(JCVideoPlayer.FULLSCREEN_ID); if (old != null) { vp.removeView(old); } try { Constructor<JCVideoPlayer> constructor = _class.getConstructor(Context.class); JCVideoPlayer jcVideoPlayer = constructor.newInstance(context); jcVideoPlayer.setId(JCVideoPlayer.FULLSCREEN_ID); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); vp.addView(jcVideoPlayer, lp); // final Animation ra = AnimationUtils.loadAnimation(context, R.anim.start_fullscreen); // jcVideoPlayer.setAnimation(ra); jcVideoPlayer.setUp(url, JCVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN, objects); jcVideoPlayer.addTextureView(); jcVideoPlayer.startButton.performClick(); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static void hideSupportActionBar(Context context) { if (ACTION_BAR_EXIST) { ActionBar ab = JCUtils.getAppCompActivity(context).getSupportActionBar(); if (ab != null) { ab.setShowHideAnimationEnabled(false); ab.hide(); } } if (TOOL_BAR_EXIST) { JCUtils.getAppCompActivity(context).getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } } public static void showSupportActionBar(Context context) { if (ACTION_BAR_EXIST) { ActionBar ab = JCUtils.getAppCompActivity(context).getSupportActionBar(); if (ab != null) { ab.setShowHideAnimationEnabled(false); ab.show(); } } if (TOOL_BAR_EXIST) { JCUtils.getAppCompActivity(context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); } } public static class JCAutoFullscreenListener implements SensorEventListener { @Override public void onSensorChanged(SensorEvent event) {//可以得到传感器实时测量出来的变化值 final float x = event.values[SensorManager.DATA_X]; float y = event.values[SensorManager.DATA_Y]; float z = event.values[SensorManager.DATA_Z]; //过滤掉用力过猛会有一个反向的大数值 if (((x > -15 && x < -10) || (x < 15 && x > 10)) && Math.abs(y) < 1.5) { if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000) { if (JCVideoPlayerManager.getFirst() != null) { JCVideoPlayerManager.getFirst().autoFullscreen(x); } lastAutoFullscreenTime = System.currentTimeMillis(); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } } private void obtainCache() { Point videoSize = JCMediaManager.instance().getVideoSize(); if (videoSize != null) { Bitmap bitmap = JCMediaManager.textureView.getBitmap(videoSize.x, videoSize.y); if (bitmap != null) { pauseSwitchCoverBitmap = bitmap; } } } public void refreshCache() { if (pauseSwitchCoverBitmap != null) { JCVideoPlayer jcVideoPlayer = ((JCVideoPlayer) JCVideoPlayerManager.getFirst()); if (jcVideoPlayer != null) { jcVideoPlayer.cacheImageView.setImageBitmap(pauseSwitchCoverBitmap); jcVideoPlayer.cacheImageView.setVisibility(VISIBLE); } } } public void clearCacheImage() { pauseSwitchCoverBitmap = null; cacheImageView.setImageBitmap(null); } public void showWifiDialog() { } public void showProgressDialog(float deltaX, String seekTime, int seekTimePosition, String totalTime, int totalTimeDuration) { } public void dismissProgressDialog() { } public void showVolumeDialog(float deltaY, int volumePercent) { } public void dismissVolumeDialog() { } public abstract int getLayoutId(); }