clazz = MediaPlayer.class;
+ //如果不用反射,没有url和header参数的setDataSource函数
+ Method method = clazz.getDeclaredMethod("setDataSource", String.class, Map.class);
+ method.invoke(mediaPlayer, jzvd.jzDataSource.getCurrentUrl().toString(), jzvd.jzDataSource.headerMap);
+ mediaPlayer.prepareAsync();
+ mediaPlayer.setSurface(new Surface(SAVED_SURFACE));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ @Override
+ public void start() {
+ mMediaHandler.post(() -> mediaPlayer.start());
+ }
+
+ @Override
+ public void pause() {
+ mMediaHandler.post(() -> mediaPlayer.pause());
+ }
+
+ @Override
+ public boolean isPlaying() {
+ return mediaPlayer.isPlaying();
+ }
+
+ @Override
+ public void seekTo(long time) {
+ mMediaHandler.post(() -> {
+ try {
+ mediaPlayer.seekTo((int) time);
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ @Override
+ public void release() {//not perfect change you later
+ if (mMediaHandler != null && mMediaHandlerThread != null && mediaPlayer != null) {//不知道有没有妖孽
+ HandlerThread tmpHandlerThread = mMediaHandlerThread;
+ MediaPlayer tmpMediaPlayer = mediaPlayer;
+ JZMediaInterface.SAVED_SURFACE = null;
+
+ mMediaHandler.post(() -> {
+ tmpMediaPlayer.setSurface(null);
+ tmpMediaPlayer.release();
+ tmpHandlerThread.quit();
+ });
+ mediaPlayer = null;
+ }
+ }
+
+ //TODO 测试这种问题是否在threadHandler中是否正常,所有的操作mediaplayer是否不需要thread,挨个测试,是否有问题
+ @Override
+ public long getCurrentPosition() {
+ if (mediaPlayer != null) {
+ return mediaPlayer.getCurrentPosition();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public long getDuration() {
+ if (mediaPlayer != null) {
+ return mediaPlayer.getDuration();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public void setVolume(float leftVolume, float rightVolume) {
+ if (mMediaHandler == null) return;
+ mMediaHandler.post(() -> {
+ if (mediaPlayer != null) mediaPlayer.setVolume(leftVolume, rightVolume);
+ });
+ }
+
+ @Override
+ public void setSpeed(float speed) {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ PlaybackParams pp = mediaPlayer.getPlaybackParams();
+ pp.setSpeed(speed);
+ mediaPlayer.setPlaybackParams(pp);
+ }
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer mediaPlayer) {
+ handler.post(() -> jzvd.onPrepared());//如果是mp3音频,走这里
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer mediaPlayer) {
+ handler.post(() -> jzvd.onCompletion());
+ }
+
+ @Override
+ public void onBufferingUpdate(MediaPlayer mediaPlayer, final int percent) {
+ handler.post(() -> jzvd.setBufferProgress(percent));
+ }
+
+ @Override
+ public void onSeekComplete(MediaPlayer mediaPlayer) {
+ handler.post(() -> jzvd.onSeekComplete());
+ }
+
+ @Override
+ public boolean onError(MediaPlayer mediaPlayer, final int what, final int extra) {
+ handler.post(() -> jzvd.onError(what, extra));
+ return true;
+ }
+
+ @Override
+ public boolean onInfo(MediaPlayer mediaPlayer, final int what, final int extra) {
+ handler.post(() -> jzvd.onInfo(what, extra));
+ return false;
+ }
+
+ @Override
+ public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) {
+ handler.post(() -> jzvd.onVideoSizeChanged(width, height));
+ }
+
+ @Override
+ public void setSurface(Surface surface) {
+ mediaPlayer.setSurface(surface);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ if (SAVED_SURFACE == null) {
+ SAVED_SURFACE = surface;
+ prepare();
+ } else {
+ jzvd.textureView.setSurfaceTexture(SAVED_SURFACE);
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+
+ }
+}
diff --git a/library/src/main/java/cn/jzvd/JZTextureView.java b/library/src/main/java/cn/jzvd/JZTextureView.java
new file mode 100644
index 0000000..0e850c1
--- /dev/null
+++ b/library/src/main/java/cn/jzvd/JZTextureView.java
@@ -0,0 +1,161 @@
+package cn.jzvd;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.View;
+
+/**
+ * 参照Android系统的VideoView的onMeasure方法
+ *
注意!relativelayout中无法全屏,要嵌套一个linearlayout
+ * Referring Android system Video View of onMeasure method
+ *
NOTE! Can not fullscreen relativelayout, to nest a linearlayout
+ * Created by Nathen
+ * On 2016/06/02 00:01
+ */
+public class JZTextureView extends TextureView {
+ protected static final String TAG = "JZResizeTextureView";
+
+ public int currentVideoWidth = 0;
+ public int currentVideoHeight = 0;
+
+ public JZTextureView(Context context) {
+ super(context);
+ currentVideoWidth = 0;
+ currentVideoHeight = 0;
+ }
+
+ public JZTextureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ currentVideoWidth = 0;
+ currentVideoHeight = 0;
+ }
+
+ public void setVideoSize(int currentVideoWidth, int currentVideoHeight) {
+ if (this.currentVideoWidth != currentVideoWidth || this.currentVideoHeight != currentVideoHeight) {
+ this.currentVideoWidth = currentVideoWidth;
+ this.currentVideoHeight = currentVideoHeight;
+ requestLayout();
+ }
+ }
+
+ @Override
+ public void setRotation(float rotation) {
+ if (rotation != getRotation()) {
+ super.setRotation(rotation);
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ Log.i(TAG, "onMeasure " + " [" + this.hashCode() + "] ");
+ int viewRotation = (int) getRotation();
+ int videoWidth = currentVideoWidth;
+ int videoHeight = currentVideoHeight;
+
+
+ int parentHeight = ((View) getParent()).getMeasuredHeight();
+ int parentWidth = ((View) getParent()).getMeasuredWidth();
+ if (parentWidth != 0 && parentHeight != 0 && videoWidth != 0 && videoHeight != 0) {
+ if (Jzvd.VIDEO_IMAGE_DISPLAY_TYPE == Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_PARENT) {
+ if (viewRotation == 90 || viewRotation == 270) {
+ int tempSize = parentWidth;
+ parentWidth = parentHeight;
+ parentHeight = tempSize;
+ }
+ /**强制充满**/
+ videoHeight = videoWidth * parentHeight / parentWidth;
+ }
+ }
+
+ // 如果判断成立,则说明显示的TextureView和本身的位置是有90度的旋转的,所以需要交换宽高参数。
+ if (viewRotation == 90 || viewRotation == 270) {
+ int tempMeasureSpec = widthMeasureSpec;
+ widthMeasureSpec = heightMeasureSpec;
+ heightMeasureSpec = tempMeasureSpec;
+ }
+
+ int width = getDefaultSize(videoWidth, widthMeasureSpec);
+ int height = getDefaultSize(videoHeight, heightMeasureSpec);
+ if (videoWidth > 0 && videoHeight > 0) {
+
+ int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ Log.i(TAG, "widthMeasureSpec [" + MeasureSpec.toString(widthMeasureSpec) + "]");
+ Log.i(TAG, "heightMeasureSpec [" + MeasureSpec.toString(heightMeasureSpec) + "]");
+
+ if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
+ // the size is fixed
+ width = widthSpecSize;
+ height = heightSpecSize;
+ // for compatibility, we adjust size based on aspect ratio
+ if (videoWidth * height < width * videoHeight) {
+ width = height * videoWidth / videoHeight;
+ } else if (videoWidth * height > width * videoHeight) {
+ height = width * videoHeight / videoWidth;
+ }
+ } else if (widthSpecMode == MeasureSpec.EXACTLY) {
+ // only the width is fixed, adjust the height to match aspect ratio if possible
+ width = widthSpecSize;
+ height = width * videoHeight / videoWidth;
+ if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
+ // couldn't match aspect ratio within the constraints
+ height = heightSpecSize;
+ width = height * videoWidth / videoHeight;
+ }
+ } else if (heightSpecMode == MeasureSpec.EXACTLY) {
+ // only the height is fixed, adjust the width to match aspect ratio if possible
+ height = heightSpecSize;
+ width = height * videoWidth / videoHeight;
+ if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
+ // couldn't match aspect ratio within the constraints
+ width = widthSpecSize;
+ height = width * videoHeight / videoWidth;
+ }
+ } else {
+ // neither the width nor the height are fixed, try to use actual video size
+ width = videoWidth;
+ height = videoHeight;
+ if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
+ // too tall, decrease both width and height
+ height = heightSpecSize;
+ width = height * videoWidth / videoHeight;
+ }
+ if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
+ // too wide, decrease both width and height
+ width = widthSpecSize;
+ height = width * videoHeight / videoWidth;
+ }
+ }
+ } else {
+ // no size yet, just adopt the given spec sizes
+ }
+ if (parentWidth != 0 && parentHeight != 0 && videoWidth != 0 && videoHeight != 0) {
+ if (Jzvd.VIDEO_IMAGE_DISPLAY_TYPE == Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_ORIGINAL) {
+ /**原图**/
+ height = videoHeight;
+ width = videoWidth;
+ } else if (Jzvd.VIDEO_IMAGE_DISPLAY_TYPE == Jzvd.VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP) {
+ if (viewRotation == 90 || viewRotation == 270) {
+ int tempSize = parentWidth;
+ parentWidth = parentHeight;
+ parentHeight = tempSize;
+ }
+ /**充满剪切**/
+ if (((double) videoHeight / videoWidth) > ((double) parentHeight / parentWidth)) {
+ height = (int) (((double) parentWidth / (double) width * (double) height));
+ width = parentWidth;
+ } else if (((double) videoHeight / videoWidth) < ((double) parentHeight / parentWidth)) {
+ width = (int) (((double) parentHeight / (double) height * (double) width));
+ height = parentHeight;
+ }
+ }
+ }
+ setMeasuredDimension(width, height);
+ }
+}
diff --git a/library/src/main/java/cn/jzvd/JZUtils.java b/library/src/main/java/cn/jzvd/JZUtils.java
new file mode 100644
index 0000000..a14f2a8
--- /dev/null
+++ b/library/src/main/java/cn/jzvd/JZUtils.java
@@ -0,0 +1,199 @@
+package cn.jzvd;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.util.Formatter;
+import java.util.Locale;
+
+/**
+ * Created by Nathen
+ * On 2016/02/21 12:25
+ */
+public class JZUtils {
+ public static final String TAG = "JZVD";
+ public static int SYSTEM_UI = 0;
+
+ public static String stringForTime(long timeMs) {
+ if (timeMs <= 0 || timeMs >= 24 * 60 * 60 * 1000) {
+ return "00:00";
+ }
+ long totalSeconds = timeMs / 1000;
+ int seconds = (int) (totalSeconds % 60);
+ int minutes = (int) ((totalSeconds / 60) % 60);
+ int hours = (int) (totalSeconds / 3600);
+ StringBuilder stringBuilder = new StringBuilder();
+ Formatter mFormatter = new Formatter(stringBuilder, Locale.getDefault());
+ if (hours > 0) {
+ return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
+ } else {
+ return mFormatter.format("%02d:%02d", minutes, seconds).toString();
+ }
+ }
+
+ /**
+ * This method requires the caller to hold the permission ACCESS_NETWORK_STATE.
+ *
+ * @param context context
+ * @return if wifi is connected,return true
+ */
+ public static boolean isWifiConnected(Context context) {
+ ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
+ return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
+ }
+
+ /**
+ * Get activity from context object
+ *
+ * @param context context
+ * @return object of Activity or null if it is not Activity
+ */
+ public static Activity scanForActivity(Context context) {
+ if (context == null) return null;
+
+ if (context instanceof Activity) {
+ return (Activity) context;
+ } else if (context instanceof ContextWrapper) {
+ return scanForActivity(((ContextWrapper) context).getBaseContext());
+ }
+
+ return null;
+ }
+
+ public static void setRequestedOrientation(Context context, int orientation) {
+ if (JZUtils.scanForActivity(context) != null) {
+ JZUtils.scanForActivity(context).setRequestedOrientation(
+ orientation);
+ } else {
+ JZUtils.scanForActivity(context).setRequestedOrientation(
+ orientation);
+ }
+ }
+
+ public static Window getWindow(Context context) {
+ if (JZUtils.scanForActivity(context) != null) {
+ return JZUtils.scanForActivity(context).getWindow();
+ } else {
+ return JZUtils.scanForActivity(context).getWindow();
+ }
+ }
+
+ public static int dip2px(Context context, float dpValue) {
+ final float scale = context.getResources().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ public static void saveProgress(Context context, Object url, long progress) {
+ if (!Jzvd.SAVE_PROGRESS) return;
+ Log.i(TAG, "saveProgress: " + progress);
+ if (progress < 5000) {
+ progress = 0;
+ }
+ SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS",
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = spn.edit();
+ editor.putLong("newVersion:" + url.toString(), progress).apply();
+ }
+
+ public static long getSavedProgress(Context context, Object url) {
+ if (!Jzvd.SAVE_PROGRESS) return 0;
+ SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS",
+ Context.MODE_PRIVATE);
+ return spn.getLong("newVersion:" + url.toString(), 0);
+ }
+
+ /**
+ * if url == null, clear all progress
+ *
+ * @param context context
+ * @param url if url!=null clear this url progress
+ */
+ public static void clearSavedProgress(Context context, Object url) {
+ if (url == null) {
+ SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS",
+ Context.MODE_PRIVATE);
+ spn.edit().clear().apply();
+ } else {
+ SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS",
+ Context.MODE_PRIVATE);
+ spn.edit().putLong("newVersion:" + url.toString(), 0).apply();
+ }
+ }
+
+ @SuppressLint("RestrictedApi")
+ public static void showStatusBar(Context context) {
+ if (Jzvd.TOOL_BAR_EXIST) {
+ JZUtils.getWindow(context).clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+
+ //如果是沉浸式的,全屏前就没有状态栏
+ @SuppressLint("RestrictedApi")
+ public static void hideStatusBar(Context context) {
+ if (Jzvd.TOOL_BAR_EXIST) {
+ JZUtils.getWindow(context).setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+
+ @SuppressLint("NewApi")
+ public static void hideSystemUI(Context context) {
+ int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ ;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ }
+ SYSTEM_UI = JZUtils.getWindow(context).getDecorView().getSystemUiVisibility();
+ JZUtils.getWindow(context).getDecorView().setSystemUiVisibility(uiOptions);
+
+ }
+
+ @SuppressLint("NewApi")
+ public static void showSystemUI(Context context) {
+ int uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
+ JZUtils.getWindow(context).getDecorView().setSystemUiVisibility(SYSTEM_UI);
+ }
+
+ //获取状态栏的高度
+ public static int getStatusBarHeight(Context context) {
+ Resources resources = context.getResources();
+ int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
+ int height = resources.getDimensionPixelSize(resourceId);
+ return height;
+ }
+
+ //获取NavigationBar的高度
+ public static int getNavigationBarHeight(Context context) {
+ boolean var1 = ViewConfiguration.get(context).hasPermanentMenuKey();
+ int var2;
+ return (var2 = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android")) > 0 && !var1 ? context.getResources().getDimensionPixelSize(var2) : 0;
+ }
+
+ //获取屏幕的宽度
+ public static int getScreenWidth(Context context) {
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ return dm.widthPixels;
+ }
+
+ //获取屏幕的高度
+ public static int getScreenHeight(Context context) {
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ return dm.heightPixels;
+ }
+
+}
diff --git a/library/src/main/java/cn/jzvd/Jzvd.java b/library/src/main/java/cn/jzvd/Jzvd.java
new file mode 100644
index 0000000..2b7ad44
--- /dev/null
+++ b/library/src/main/java/cn/jzvd/Jzvd.java
@@ -0,0 +1,1135 @@
+package cn.jzvd;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedList;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Created by Nathen on 16/7/30.
+ */
+public abstract class Jzvd extends FrameLayout implements View.OnClickListener, SeekBar.OnSeekBarChangeListener, View.OnTouchListener {
+
+ public static final String TAG = "JZVD";
+ public static final int SCREEN_NORMAL = 0;
+ public static final int SCREEN_FULLSCREEN = 1;
+ public static final int SCREEN_TINY = 2;
+ public static final int STATE_IDLE = -1;
+ public static final int STATE_NORMAL = 0;
+ public static final int STATE_PREPARING = 1;
+ public static final int STATE_PREPARING_CHANGE_URL = 2;
+ public static final int STATE_PREPARING_PLAYING = 3;
+ public static final int STATE_PREPARED = 4;
+ public static final int STATE_PLAYING = 5;
+ public static final int STATE_PAUSE = 6;
+ public static final int STATE_AUTO_COMPLETE = 7;
+ public static final int STATE_ERROR = 8;
+ public static final int VIDEO_IMAGE_DISPLAY_TYPE_ADAPTER = 0;//DEFAULT
+ public static final int VIDEO_IMAGE_DISPLAY_TYPE_FILL_PARENT = 1;
+ public static final int VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP = 2;
+ public static final int VIDEO_IMAGE_DISPLAY_TYPE_ORIGINAL = 3;
+ public static final int THRESHOLD = 80;
+ public static Jzvd CURRENT_JZVD;
+ public static LinkedList CONTAINER_LIST = new LinkedList<>();
+ public static boolean TOOL_BAR_EXIST = true;
+ public static int FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+ public static int NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+ public static boolean SAVE_PROGRESS = true;
+ public static boolean WIFI_TIP_DIALOG_SHOWED = false;
+ public static int VIDEO_IMAGE_DISPLAY_TYPE = 0;
+ public static long lastAutoFullscreenTime = 0;
+ public static int ON_PLAY_PAUSE_TMP_STATE = 0;//这个考虑不放到库里,去自定义
+ public static int backUpBufferState = -1;
+ public static float PROGRESS_DRAG_RATE = 1f;//进度条滑动阻尼系数 越大播放进度条滑动越慢
+ public static AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {//是否新建个class,代码更规矩,并且变量的位置也很尴尬
+ @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:
+ try {
+ Jzvd player = CURRENT_JZVD;
+ if (player != null && player.state == Jzvd.STATE_PLAYING) {
+ player.startButton.performClick();
+ }
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT [" + this.hashCode() + "]");
+ break;
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ break;
+ }
+ }
+ };
+ public int state = -1;
+ public int screen = -1;
+ public JZDataSource jzDataSource;
+ public int widthRatio = 0;
+ public int heightRatio = 0;
+ public Class mediaInterfaceClass;
+ public JZMediaInterface mediaInterface;
+ public int positionInList = -1;//很想干掉它
+ public int videoRotation = 0;
+ public int seekToManulPosition = -1;
+ public long seekToInAdvance = 0;
+
+ public ImageView startButton;
+ public SeekBar progressBar;
+ public ImageView fullscreenButton;
+ public TextView currentTimeTextView, totalTimeTextView;
+ public ViewGroup textureViewContainer;
+ public ViewGroup topContainer, bottomContainer;
+ public JZTextureView textureView;
+ public boolean preloading = false;
+ protected long gobakFullscreenTime = 0;//这个应该重写一下,刷新列表,新增列表的刷新,不打断播放,应该是个flag
+ protected long gotoFullscreenTime = 0;
+ protected Timer UPDATE_PROGRESS_TIMER;
+ protected int mScreenWidth;
+ protected int mScreenHeight;
+ protected AudioManager mAudioManager;
+ protected ProgressTimerTask mProgressTimerTask;
+ protected boolean mTouchingProgressBar;
+ protected float mDownX;
+ protected float mDownY;
+ protected boolean mChangeVolume;
+ protected boolean mChangePosition;
+ protected boolean mChangeBrightness;
+ protected long mGestureDownPosition;
+ protected int mGestureDownVolume;
+ protected float mGestureDownBrightness;
+ protected long mSeekTimePosition;
+ protected Context jzvdContext;
+ protected long mCurrentPosition;
+ /**
+ * 如果不在列表中可以不加block
+ */
+ protected ViewGroup.LayoutParams blockLayoutParams;
+ protected int blockIndex;
+ protected int blockWidth;
+ protected int blockHeight;
+
+ public Jzvd(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public Jzvd(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ /**
+ * 增加准备状态逻辑
+ */
+ public static void goOnPlayOnResume() {
+ if (CURRENT_JZVD != null) {
+ if (CURRENT_JZVD.state == Jzvd.STATE_PAUSE) {
+ if (ON_PLAY_PAUSE_TMP_STATE == STATE_PAUSE) {
+ CURRENT_JZVD.onStatePause();
+ CURRENT_JZVD.mediaInterface.pause();
+ } else {
+ CURRENT_JZVD.onStatePlaying();
+ CURRENT_JZVD.mediaInterface.start();
+ }
+ ON_PLAY_PAUSE_TMP_STATE = 0;
+ } else if (CURRENT_JZVD.state == Jzvd.STATE_PREPARING) {
+ //准备状态暂停后的
+ CURRENT_JZVD.startVideo();
+ }
+ if (CURRENT_JZVD.screen == Jzvd.SCREEN_FULLSCREEN) {
+ JZUtils.hideStatusBar(CURRENT_JZVD.jzvdContext);
+ JZUtils.hideSystemUI(CURRENT_JZVD.jzvdContext);
+ }
+ }
+ }
+
+ /**
+ * 增加准备状态逻辑
+ */
+ public static void goOnPlayOnPause() {
+ if (CURRENT_JZVD != null) {
+ if (CURRENT_JZVD.state == Jzvd.STATE_AUTO_COMPLETE ||
+ CURRENT_JZVD.state == Jzvd.STATE_NORMAL ||
+ CURRENT_JZVD.state == Jzvd.STATE_ERROR) {
+ Jzvd.releaseAllVideos();
+ } else if (CURRENT_JZVD.state == Jzvd.STATE_PREPARING) {
+ //准备状态暂停的逻辑
+ Jzvd.setCurrentJzvd(CURRENT_JZVD);
+ CURRENT_JZVD.state = STATE_PREPARING;
+ } else {
+ ON_PLAY_PAUSE_TMP_STATE = CURRENT_JZVD.state;
+ CURRENT_JZVD.onStatePause();
+ CURRENT_JZVD.mediaInterface.pause();
+ }
+ }
+ }
+
+ public static void startFullscreenDirectly(Context context, Class _class, String url, String title) {
+ startFullscreenDirectly(context, _class, new JZDataSource(url, title));
+ }
+
+ public static void startFullscreenDirectly(Context context, Class _class, JZDataSource jzDataSource) {
+ JZUtils.hideStatusBar(context);
+ JZUtils.setRequestedOrientation(context, FULLSCREEN_ORIENTATION);
+ JZUtils.hideSystemUI(context);
+
+ ViewGroup vp = (ViewGroup) JZUtils.scanForActivity(context).getWindow().getDecorView();
+ try {
+ Constructor constructor = _class.getConstructor(Context.class);
+ final Jzvd jzvd = constructor.newInstance(context);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ vp.addView(jzvd, lp);
+ jzvd.setUp(jzDataSource, JzvdStd.SCREEN_FULLSCREEN);
+ jzvd.startVideo();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void releaseAllVideos() {
+ Log.d(TAG, "releaseAllVideos");
+ if (CURRENT_JZVD != null) {
+ CURRENT_JZVD.reset();
+ CURRENT_JZVD = null;
+ }
+ }
+
+ public static boolean backPress() {
+ Log.i(TAG, "backPress");
+ if (CONTAINER_LIST.size() != 0 && CURRENT_JZVD != null) {//判断条件,因为当前所有goBack都是回到普通窗口
+ CURRENT_JZVD.gotoNormalScreen();
+ return true;
+ } else if (CONTAINER_LIST.size() == 0 && CURRENT_JZVD != null && CURRENT_JZVD.screen != SCREEN_NORMAL) {//退出直接进入的全屏
+ CURRENT_JZVD.clearFloatScreen();
+ return true;
+ }
+ return false;
+ }
+
+ public static void setCurrentJzvd(Jzvd jzvd) {
+ if (CURRENT_JZVD != null) CURRENT_JZVD.reset();
+ CURRENT_JZVD = jzvd;
+ }
+
+ public static void setTextureViewRotation(int rotation) {
+ if (CURRENT_JZVD != null && CURRENT_JZVD.textureView != null) {
+ CURRENT_JZVD.textureView.setRotation(rotation);
+ }
+ }
+
+ public static void setVideoImageDisplayType(int type) {
+ Jzvd.VIDEO_IMAGE_DISPLAY_TYPE = type;
+ if (CURRENT_JZVD != null && CURRENT_JZVD.textureView != null) {
+ CURRENT_JZVD.textureView.requestLayout();
+ }
+ }
+
+ public abstract int getLayoutId();
+
+ public void init(Context context) {
+ View.inflate(context, getLayoutId(), this);
+ jzvdContext = context;
+ startButton = findViewById(R.id.start);
+ fullscreenButton = findViewById(R.id.fullscreen);
+ progressBar = findViewById(R.id.bottom_seek_progress);
+ currentTimeTextView = findViewById(R.id.current);
+ totalTimeTextView = findViewById(R.id.total);
+ bottomContainer = findViewById(R.id.layout_bottom);
+ textureViewContainer = findViewById(R.id.surface_container);
+ topContainer = findViewById(R.id.layout_top);
+
+ if (startButton == null) {
+ startButton = new ImageView(context);
+ }
+ if (fullscreenButton == null) {
+ fullscreenButton = new ImageView(context);
+ }
+ if (progressBar == null) {
+ progressBar = new SeekBar(context);
+ }
+ if (currentTimeTextView == null) {
+ currentTimeTextView = new TextView(context);
+ }
+ if (totalTimeTextView == null) {
+ totalTimeTextView = new TextView(context);
+ }
+ if (bottomContainer == null) {
+ bottomContainer = new LinearLayout(context);
+ }
+ if (textureViewContainer == null) {
+ textureViewContainer = new FrameLayout(context);
+ }
+ if (topContainer == null) {
+ topContainer = new RelativeLayout(context);
+ }
+
+ 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;
+
+ state = STATE_IDLE;
+ }
+
+ public void setUp(String url, String title) {
+ setUp(new JZDataSource(url, title), SCREEN_NORMAL);
+ }
+
+ public void setUp(String url, String title, int screen) {
+ setUp(new JZDataSource(url, title), screen);
+ }
+
+ public void setUp(JZDataSource jzDataSource, int screen) {
+ setUp(jzDataSource, screen, JZMediaSystem.class);
+ }
+
+ public void setUp(String url, String title, int screen, Class mediaInterfaceClass) {
+ setUp(new JZDataSource(url, title), screen, mediaInterfaceClass);
+ }
+
+ public void setUp(JZDataSource jzDataSource, int screen, Class mediaInterfaceClass) {
+
+
+ this.jzDataSource = jzDataSource;
+ this.screen = screen;
+ onStateNormal();
+ this.mediaInterfaceClass = mediaInterfaceClass;
+ }
+
+ public void setMediaInterface(Class mediaInterfaceClass) {
+ reset();
+ this.mediaInterfaceClass = mediaInterfaceClass;
+ }
+
+ @Override
+ public void onClick(View v) {
+ int i = v.getId();
+ if (i == R.id.start) {
+ clickStart();
+ } else if (i == R.id.fullscreen) {
+ clickFullscreen();
+ }
+ }
+
+ protected void clickFullscreen() {
+ Log.i(TAG, "onClick fullscreen [" + this.hashCode() + "] ");
+ if (state == STATE_AUTO_COMPLETE) return;
+ if (screen == SCREEN_FULLSCREEN) {
+ //quit fullscreen
+ backPress();
+ } else {
+ Log.d(TAG, "toFullscreenActivity [" + this.hashCode() + "] ");
+ gotoFullscreen();
+ }
+ }
+
+ protected void clickStart() {
+ Log.i(TAG, "onClick start [" + this.hashCode() + "] ");
+ if (jzDataSource == null || jzDataSource.urlsMap.isEmpty() || jzDataSource.getCurrentUrl() == null) {
+ Toast.makeText(getContext(), getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show();
+ return;
+ }
+ if (state == STATE_NORMAL) {
+ if (!jzDataSource.getCurrentUrl().toString().startsWith("file") && !
+ jzDataSource.getCurrentUrl().toString().startsWith("/") &&
+ !JZUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) {//这个可以放到std中
+ showWifiDialog();
+ return;
+ }
+ startVideo();
+ } else if (state == STATE_PLAYING) {
+ Log.d(TAG, "pauseVideo [" + this.hashCode() + "] ");
+ mediaInterface.pause();
+ onStatePause();
+ } else if (state == STATE_PAUSE) {
+ mediaInterface.start();
+ onStatePlaying();
+ } else if (state == STATE_AUTO_COMPLETE) {
+ startVideo();
+ }
+ }
+
+
+
+ @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:
+ touchActionDown(x, y);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ touchActionMove(x, y);
+ break;
+ case MotionEvent.ACTION_UP:
+ touchActionUp();
+ break;
+ }
+ }
+ return false;
+ }
+
+ protected void touchActionUp() {
+ Log.i(TAG, "onTouch surfaceContainer actionUp [" + this.hashCode() + "] ");
+ mTouchingProgressBar = false;
+ dismissProgressDialog();
+ dismissVolumeDialog();
+ dismissBrightnessDialog();
+ if (mChangePosition) {
+ mediaInterface.seekTo(mSeekTimePosition);
+ long duration = getDuration();
+ int progress = (int) (mSeekTimePosition * 100 / (duration == 0 ? 1 : duration));
+ progressBar.setProgress(progress);
+ }
+ if (mChangeVolume) {
+ //change volume event
+ }
+ startProgressTimer();
+ }
+
+ protected void touchActionMove(float x, float y) {
+ 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 (screen == SCREEN_FULLSCREEN) {
+ //拖动的是NavigationBar和状态栏
+ if (mDownX > JZUtils.getScreenWidth(getContext()) || mDownY < JZUtils.getStatusBarHeight(getContext())) {
+ return;
+ }
+ if (!mChangePosition && !mChangeVolume && !mChangeBrightness) {
+ if (absDeltaX > THRESHOLD || absDeltaY > THRESHOLD) {
+ cancelProgressTimer();
+ if (absDeltaX >= THRESHOLD) {
+ // 全屏模式下的CURRENT_STATE_ERROR状态下,不响应进度拖动事件.
+ // 否则会因为mediaplayer的状态非法导致App Crash
+ if (state != STATE_ERROR) {
+ mChangePosition = true;
+ mGestureDownPosition = getCurrentPositionWhenPlaying();
+ }
+ } else {
+ //如果y轴滑动距离超过设置的处理范围,那么进行滑动事件处理
+ if (mDownX < mScreenHeight * 0.5f) {//左侧改变亮度
+ mChangeBrightness = true;
+ WindowManager.LayoutParams lp = JZUtils.getWindow(getContext()).getAttributes();
+ if (lp.screenBrightness < 0) {
+ try {
+ mGestureDownBrightness = Settings.System.getInt(getContext().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
+ Log.i(TAG, "current system brightness: " + mGestureDownBrightness);
+ } catch (Settings.SettingNotFoundException e) {
+ e.printStackTrace();
+ }
+ } else {
+ mGestureDownBrightness = lp.screenBrightness * 255;
+ Log.i(TAG, "current activity brightness: " + mGestureDownBrightness);
+ }
+ } else {//右侧改变声音
+ mChangeVolume = true;
+ mGestureDownVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ }
+ }
+ }
+ }
+ }
+ if (mChangePosition) {
+ long totalTimeDuration = getDuration();
+ if (PROGRESS_DRAG_RATE <= 0) {
+ Log.d(TAG, "error PROGRESS_DRAG_RATE value");
+ PROGRESS_DRAG_RATE = 1f;
+ }
+ mSeekTimePosition = (int) (mGestureDownPosition + deltaX * totalTimeDuration / (mScreenWidth * PROGRESS_DRAG_RATE));
+ if (mSeekTimePosition > totalTimeDuration)
+ mSeekTimePosition = totalTimeDuration;
+ String seekTime = JZUtils.stringForTime(mSeekTimePosition);
+ String totalTime = JZUtils.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);
+ //dialog中显示百分比
+ int volumePercent = (int) (mGestureDownVolume * 100 / max + deltaY * 3 * 100 / mScreenHeight);
+ showVolumeDialog(-deltaY, volumePercent);
+ }
+
+ if (mChangeBrightness) {
+ deltaY = -deltaY;
+ int deltaV = (int) (255 * deltaY * 3 / mScreenHeight);
+ WindowManager.LayoutParams params = JZUtils.getWindow(getContext()).getAttributes();
+ if (((mGestureDownBrightness + deltaV) / 255) >= 1) {//这和声音有区别,必须自己过滤一下负值
+ params.screenBrightness = 1;
+ } else if (((mGestureDownBrightness + deltaV) / 255) <= 0) {
+ params.screenBrightness = 0.01f;
+ } else {
+ params.screenBrightness = (mGestureDownBrightness + deltaV) / 255;
+ }
+ JZUtils.getWindow(getContext()).setAttributes(params);
+ //dialog中显示百分比
+ int brightnessPercent = (int) (mGestureDownBrightness * 100 / 255 + deltaY * 3 * 100 / mScreenHeight);
+ showBrightnessDialog(brightnessPercent);
+// mDownY = y;
+ }
+ }
+
+ protected void touchActionDown(float x, float y) {
+ Log.i(TAG, "onTouch surfaceContainer actionDown [" + this.hashCode() + "] ");
+ mTouchingProgressBar = true;
+
+ mDownX = x;
+ mDownY = y;
+ mChangeVolume = false;
+ mChangePosition = false;
+ mChangeBrightness = false;
+ }
+
+ public void onStateNormal() {
+ Log.i(TAG, "onStateNormal " + " [" + this.hashCode() + "] ");
+ state = STATE_NORMAL;
+ cancelProgressTimer();
+ if (mediaInterface != null) mediaInterface.release();
+ }
+
+ public void onStatePreparing() {
+ Log.i(TAG, "onStatePreparing " + " [" + this.hashCode() + "] ");
+ state = STATE_PREPARING;
+ resetProgressAndTime();
+ }
+
+ public void onStatePreparingPlaying() {
+ Log.i(TAG, "onStatePreparingPlaying " + " [" + this.hashCode() + "] ");
+ state = STATE_PREPARING_PLAYING;
+ }
+
+ public void onStatePreparingChangeUrl() {
+ Log.i(TAG, "onStatePreparingChangeUrl " + " [" + this.hashCode() + "] ");
+ state = STATE_PREPARING_CHANGE_URL;
+
+ releaseAllVideos();
+ startVideo();
+
+// mediaInterface.prepare();
+ }
+
+ public void changeUrl(JZDataSource jzDataSource, long seekToInAdvance) {
+ this.jzDataSource = jzDataSource;
+ this.seekToInAdvance = seekToInAdvance;
+ onStatePreparingChangeUrl();
+ }
+
+ public void onPrepared() {
+ Log.i(TAG, "onPrepared " + " [" + this.hashCode() + "] ");
+ state = STATE_PREPARED;
+ if (!preloading) {
+ mediaInterface.start();//这里原来是非县城
+ preloading = false;
+ }
+ if (jzDataSource.getCurrentUrl().toString().toLowerCase().contains("mp3") ||
+ jzDataSource.getCurrentUrl().toString().toLowerCase().contains("wma") ||
+ jzDataSource.getCurrentUrl().toString().toLowerCase().contains("aac") ||
+ jzDataSource.getCurrentUrl().toString().toLowerCase().contains("m4a") ||
+ jzDataSource.getCurrentUrl().toString().toLowerCase().contains("wav")) {
+ onStatePlaying();
+ }
+ }
+
+ public void startPreloading() {
+ preloading = true;
+ startVideo();
+ }
+
+ /**
+ * 如果STATE_PREPARED就播放,如果没准备完成就走正常的播放函数startVideo();
+ */
+ public void startVideoAfterPreloading() {
+ if (state == STATE_PREPARED) {
+ mediaInterface.start();
+ } else {
+ preloading = false;
+ startVideo();
+ }
+ }
+
+ public void onStatePlaying() {
+ Log.i(TAG, "onStatePlaying " + " [" + this.hashCode() + "] ");
+ if (state == STATE_PREPARED) {//如果是准备完成视频后第一次播放,先判断是否需要跳转进度。
+ if (seekToInAdvance != 0) {
+ mediaInterface.seekTo(seekToInAdvance);
+ seekToInAdvance = 0;
+ } else {
+ long position = JZUtils.getSavedProgress(getContext(), jzDataSource.getCurrentUrl());
+ if (position != 0) {
+ mediaInterface.seekTo(position);//这里为什么区分开呢,第一次的播放和resume播放是不一样的。 这里怎么区分是一个问题。然后
+ }
+ }
+ }
+ state = STATE_PLAYING;
+ startProgressTimer();
+ }
+
+ public void onStatePause() {
+ Log.i(TAG, "onStatePause " + " [" + this.hashCode() + "] ");
+ state = STATE_PAUSE;
+ startProgressTimer();
+ }
+
+ public void onStateError() {
+ Log.i(TAG, "onStateError " + " [" + this.hashCode() + "] ");
+ state = STATE_ERROR;
+ cancelProgressTimer();
+ }
+
+ public void onStateAutoComplete() {
+ Log.i(TAG, "onStateAutoComplete " + " [" + this.hashCode() + "] ");
+ state = STATE_AUTO_COMPLETE;
+ cancelProgressTimer();
+ progressBar.setProgress(100);
+ currentTimeTextView.setText(totalTimeTextView.getText());
+ }
+
+ public void onInfo(int what, int extra) {
+ Log.d(TAG, "onInfo what - " + what + " extra - " + extra);
+ if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
+ Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START");
+ if (state == Jzvd.STATE_PREPARED
+ || state == Jzvd.STATE_PREPARING_CHANGE_URL
+ || state == Jzvd.STATE_PREPARING_PLAYING) {
+ onStatePlaying();//开始渲染图像,真正进入playing状态
+ }
+ } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
+ Log.d(TAG, "MEDIA_INFO_BUFFERING_START");
+ backUpBufferState = state;
+ setState(STATE_PREPARING_PLAYING);
+ } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
+ Log.d(TAG, "MEDIA_INFO_BUFFERING_END");
+ if (backUpBufferState != -1) {
+ setState(backUpBufferState);
+ backUpBufferState = -1;
+ }
+ }
+ }
+
+ public void onError(int what, int extra) {
+ Log.e(TAG, "onError " + what + " - " + extra + " [" + this.hashCode() + "] ");
+ if (what != 38 && extra != -38 && what != -38 && extra != 38 && extra != -19) {
+ onStateError();
+ mediaInterface.release();
+ }
+ }
+
+ public void onCompletion() {
+ Runtime.getRuntime().gc();
+ Log.i(TAG, "onAutoCompletion " + " [" + this.hashCode() + "] ");
+ cancelProgressTimer();
+ dismissBrightnessDialog();
+ dismissProgressDialog();
+ dismissVolumeDialog();
+ onStateAutoComplete();
+ mediaInterface.release();
+ JZUtils.scanForActivity(getContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ JZUtils.saveProgress(getContext(), jzDataSource.getCurrentUrl(), 0);
+
+ if (screen == SCREEN_FULLSCREEN) {
+ if (CONTAINER_LIST.size() == 0) {
+ clearFloatScreen();//直接进入全屏
+ } else {
+ gotoNormalCompletion();
+ }
+ }
+ }
+
+ public void gotoNormalCompletion() {
+ gobakFullscreenTime = System.currentTimeMillis();//退出全屏
+ ViewGroup vg = (ViewGroup) (JZUtils.scanForActivity(jzvdContext)).getWindow().getDecorView();
+ vg.removeView(this);
+ textureViewContainer.removeView(textureView);
+ CONTAINER_LIST.getLast().removeViewAt(blockIndex);//remove block
+ CONTAINER_LIST.getLast().addView(this, blockIndex, blockLayoutParams);
+ CONTAINER_LIST.pop();
+ setScreenNormal();
+ JZUtils.showStatusBar(jzvdContext);
+ JZUtils.setRequestedOrientation(jzvdContext, NORMAL_ORIENTATION);
+ JZUtils.showSystemUI(jzvdContext);
+ }
+
+ /**
+ * 多数表现为中断当前播放
+ */
+ public void reset() {
+ Log.i(TAG, "reset " + " [" + this.hashCode() + "] ");
+ if (state == STATE_PLAYING || state == STATE_PAUSE) {
+ long position = getCurrentPositionWhenPlaying();
+ JZUtils.saveProgress(getContext(), jzDataSource.getCurrentUrl(), position);
+ }
+ cancelProgressTimer();
+ dismissBrightnessDialog();
+ dismissProgressDialog();
+ dismissVolumeDialog();
+ onStateNormal();
+ textureViewContainer.removeAllViews();
+
+ AudioManager mAudioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
+ JZUtils.scanForActivity(getContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (mediaInterface != null) mediaInterface.release();
+ }
+
+ /**
+ * 里面的的onState...()其实就是setState...(),因为要可以被复写,所以参考Activity的onCreate(),onState..()的方式看着舒服一些,老铁们有何高见。
+ *
+ * @param state stateId
+ */
+ public void setState(int state) {
+ switch (state) {
+ case STATE_NORMAL:
+ onStateNormal();
+ break;
+ case STATE_PREPARING:
+ onStatePreparing();
+ break;
+ case STATE_PREPARING_PLAYING:
+ onStatePreparingPlaying();
+ break;
+ case STATE_PREPARING_CHANGE_URL:
+ onStatePreparingChangeUrl();
+ break;
+ case STATE_PLAYING:
+ onStatePlaying();
+ break;
+ case STATE_PAUSE:
+ onStatePause();
+ break;
+ case STATE_ERROR:
+ onStateError();
+ break;
+ case STATE_AUTO_COMPLETE:
+ onStateAutoComplete();
+ break;
+ }
+ }
+
+ public void setScreen(int screen) {//特殊的个别的进入全屏的按钮在这里设置 只有setup的时候能用上
+ switch (screen) {
+ case SCREEN_NORMAL:
+ setScreenNormal();
+ break;
+ case SCREEN_FULLSCREEN:
+ setScreenFullscreen();
+ break;
+ case SCREEN_TINY:
+ setScreenTiny();
+ break;
+ }
+ }
+
+ public void startVideo() {
+ Log.d(TAG, "startVideo [" + this.hashCode() + "] ");
+ setCurrentJzvd(this);
+ try {
+ Constructor constructor = mediaInterfaceClass.getConstructor(Jzvd.class);
+ this.mediaInterface = constructor.newInstance(this);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ addTextureView();
+ mAudioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ onStatePreparing();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (screen == SCREEN_FULLSCREEN || screen == SCREEN_TINY) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
+ if (widthRatio != 0 && heightRatio != 0) {
+ int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+ int specHeight = (int) ((specWidth * (float) heightRatio) / widthRatio);
+ setMeasuredDimension(specWidth, specHeight);
+
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(specWidth, MeasureSpec.EXACTLY);
+ int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.EXACTLY);
+ getChildAt(0).measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ }
+
+ public void addTextureView() {
+ Log.d(TAG, "addTextureView [" + this.hashCode() + "] ");
+ if (textureView != null) textureViewContainer.removeView(textureView);
+ textureView = new JZTextureView(getContext().getApplicationContext());
+ textureView.setSurfaceTextureListener(mediaInterface);
+
+ FrameLayout.LayoutParams layoutParams =
+ new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ Gravity.CENTER);
+ textureViewContainer.addView(textureView, layoutParams);
+ }
+
+ public void clearFloatScreen() {
+ JZUtils.showStatusBar(getContext());
+ JZUtils.setRequestedOrientation(getContext(), NORMAL_ORIENTATION);
+ JZUtils.showSystemUI(getContext());
+
+ ViewGroup vg = (ViewGroup) (JZUtils.scanForActivity(getContext())).getWindow().getDecorView();
+ vg.removeView(this);
+ if (mediaInterface != null) mediaInterface.release();
+ CURRENT_JZVD = null;
+ }
+
+ public void onVideoSizeChanged(int width, int height) {
+ Log.i(TAG, "onVideoSizeChanged " + " [" + this.hashCode() + "] ");
+ if (textureView != null) {
+ if (videoRotation != 0) {
+ textureView.setRotation(videoRotation);
+ }
+ textureView.setVideoSize(width, height);
+ }
+ }
+
+ public void startProgressTimer() {
+ Log.i(TAG, "startProgressTimer: " + " [" + this.hashCode() + "] ");
+ 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();
+ }
+ }
+
+ public void onProgress(int progress, long position, long duration) {
+// Log.d(TAG, "onProgress: progress=" + progress + " position=" + position + " duration=" + duration);
+ mCurrentPosition = position;
+ if (!mTouchingProgressBar) {
+ if (seekToManulPosition != -1) {
+ if (seekToManulPosition > progress) {
+ return;
+ } else {
+ seekToManulPosition = -1;//这个关键帧有没有必要做
+ }
+ } else {
+ if (progress != 0) progressBar.setProgress(progress);
+ }
+ }
+ if (position != 0) currentTimeTextView.setText(JZUtils.stringForTime(position));
+ totalTimeTextView.setText(JZUtils.stringForTime(duration));
+ }
+
+ public void setBufferProgress(int bufferProgress) {
+ if (bufferProgress != 0) progressBar.setSecondaryProgress(bufferProgress);
+ }
+
+ public void resetProgressAndTime() {
+ mCurrentPosition = 0;
+ progressBar.setProgress(0);
+ progressBar.setSecondaryProgress(0);
+ currentTimeTextView.setText(JZUtils.stringForTime(0));
+ totalTimeTextView.setText(JZUtils.stringForTime(0));
+ }
+
+ public long getCurrentPositionWhenPlaying() {
+ long position = 0;
+ if (state == STATE_PLAYING || state == STATE_PAUSE || state == STATE_PREPARING_PLAYING) {
+ try {
+ position = mediaInterface.getCurrentPosition();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ return position;
+ }
+ }
+ return position;
+ }
+
+ public long getDuration() {
+ long duration = 0;
+ try {
+ duration = mediaInterface.getDuration();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ return duration;
+ }
+ return duration;
+ }
+
+ @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() + "] ");
+ startProgressTimer();
+ ViewParent vpup = getParent();
+ while (vpup != null) {
+ vpup.requestDisallowInterceptTouchEvent(false);
+ vpup = vpup.getParent();
+ }
+ if (state != STATE_PLAYING &&
+ state != STATE_PAUSE) return;
+ long time = seekBar.getProgress() * getDuration() / 100;
+ seekToManulPosition = seekBar.getProgress();
+ mediaInterface.seekTo(time);
+ Log.i(TAG, "seekTo " + time + " [" + this.hashCode() + "] ");
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser) {
+ //设置这个progres对应的时间,给textview
+ long duration = getDuration();
+ currentTimeTextView.setText(JZUtils.stringForTime(progress * duration / 100));
+ }
+ }
+
+ public void cloneAJzvd(ViewGroup vg) {
+ try {
+ Constructor constructor = (Constructor) Jzvd.this.getClass().getConstructor(Context.class);
+ Jzvd jzvd = constructor.newInstance(getContext());
+ jzvd.setId(getId());
+ jzvd.setMinimumWidth(blockWidth);
+ jzvd.setMinimumHeight(blockHeight);
+ vg.addView(jzvd, blockIndex, blockLayoutParams);
+ jzvd.setUp(jzDataSource.cloneMe(), SCREEN_NORMAL, mediaInterfaceClass);
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 如果全屏或者返回全屏的视图有问题,复写这两个函数gotoScreenNormal(),根据自己布局的情况重新布局。
+ */
+ public void gotoFullscreen() {
+ gotoFullscreenTime = System.currentTimeMillis();
+ ViewGroup vg = (ViewGroup) getParent();
+ jzvdContext = vg.getContext();
+ blockLayoutParams = getLayoutParams();
+ blockIndex = vg.indexOfChild(this);
+ blockWidth = getWidth();
+ blockHeight = getHeight();
+
+ vg.removeView(this);
+ cloneAJzvd(vg);
+ CONTAINER_LIST.add(vg);
+ vg = (ViewGroup) (JZUtils.scanForActivity(jzvdContext)).getWindow().getDecorView();
+
+ ViewGroup.LayoutParams fullLayout = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ vg.addView(this, fullLayout);
+
+ setScreenFullscreen();
+ JZUtils.hideStatusBar(jzvdContext);
+ JZUtils.setRequestedOrientation(jzvdContext, FULLSCREEN_ORIENTATION);
+ JZUtils.hideSystemUI(jzvdContext);//华为手机和有虚拟键的手机全屏时可隐藏虚拟键 issue:1326
+
+ }
+
+ public void gotoNormalScreen() {//goback本质上是goto
+ gobakFullscreenTime = System.currentTimeMillis();//退出全屏
+ ViewGroup vg = (ViewGroup) (JZUtils.scanForActivity(jzvdContext)).getWindow().getDecorView();
+ vg.removeView(this);
+// CONTAINER_LIST.getLast().removeAllViews();
+ CONTAINER_LIST.getLast().removeViewAt(blockIndex);//remove block
+ CONTAINER_LIST.getLast().addView(this, blockIndex, blockLayoutParams);
+ CONTAINER_LIST.pop();
+
+ setScreenNormal();//这块可以放到jzvd中
+ JZUtils.showStatusBar(jzvdContext);
+ JZUtils.setRequestedOrientation(jzvdContext, NORMAL_ORIENTATION);
+ JZUtils.showSystemUI(jzvdContext);
+ }
+
+ public void setScreenNormal() {//TODO 这块不对呀,还需要改进,设置flag之后要设置ui,不设置ui这么写没意义呀
+ screen = SCREEN_NORMAL;
+ }
+
+ public void setScreenFullscreen() {
+ screen = SCREEN_FULLSCREEN;
+ }
+
+ public void setScreenTiny() {
+ screen = SCREEN_TINY;
+ }
+
+ // //重力感应的时候调用的函数,、、这里有重力感应的参数,暂时不能删除
+ public void autoFullscreen(float x) {//TODO写道demo中
+ if (CURRENT_JZVD != null
+ && (state == STATE_PLAYING || state == STATE_PAUSE)
+ && screen != SCREEN_FULLSCREEN
+ && screen != SCREEN_TINY) {
+ if (x > 0) {
+ JZUtils.setRequestedOrientation(getContext(), ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ } else {
+ JZUtils.setRequestedOrientation(getContext(), ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+ }
+ gotoFullscreen();
+ }
+ }
+
+ public void autoQuitFullscreen() {
+ if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000
+// && CURRENT_JZVD != null
+ && state == STATE_PLAYING
+ && screen == SCREEN_FULLSCREEN) {
+ lastAutoFullscreenTime = System.currentTimeMillis();
+ backPress();
+ }
+ }
+
+ public void onSeekComplete() {
+
+ }
+
+ public void showWifiDialog() {
+ }
+
+ public void showProgressDialog(float deltaX,
+ String seekTime, long seekTimePosition,
+ String totalTime, long totalTimeDuration) {
+ }
+
+ public void dismissProgressDialog() {
+
+ }
+
+ public void showVolumeDialog(float deltaY, int volumePercent) {
+
+ }
+
+ public void dismissVolumeDialog() {
+
+ }
+
+ public void showBrightnessDialog(int brightnessPercent) {
+
+ }
+
+ public void dismissBrightnessDialog() {
+
+ }
+
+ public Context getApplicationContext() {//这个函数必要吗
+ Context context = getContext();
+ if (context != null) {
+ Context applicationContext = context.getApplicationContext();
+ if (applicationContext != null) {
+ return applicationContext;
+ }
+ }
+ return context;
+ }
+
+ public static class JZAutoFullscreenListener 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 < -12 || x > 12) {
+ if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000) {
+ if (Jzvd.CURRENT_JZVD != null) Jzvd.CURRENT_JZVD.autoFullscreen(x);
+ lastAutoFullscreenTime = System.currentTimeMillis();
+ }
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+ }
+
+ public class ProgressTimerTask extends TimerTask {
+ @Override
+ public void run() {
+ if (state == STATE_PLAYING || state == STATE_PAUSE || state == STATE_PREPARING_PLAYING) {
+// Log.v(TAG, "onProgressUpdate " + "[" + this.hashCode() + "] ");
+ post(() -> {
+ long position = getCurrentPositionWhenPlaying();
+ long duration = getDuration();
+ int progress = (int) (position * 100 / (duration == 0 ? 1 : duration));
+ onProgress(progress, position, duration);
+ });
+ }
+ }
+ }
+
+}
diff --git a/library/src/main/java/cn/jzvd/JzvdStd.java b/library/src/main/java/cn/jzvd/JzvdStd.java
new file mode 100644
index 0000000..98812b0
--- /dev/null
+++ b/library/src/main/java/cn/jzvd/JzvdStd.java
@@ -0,0 +1,979 @@
+package cn.jzvd;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.net.ConnectivityManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Created by Nathen
+ * On 2016/04/18 16:15
+ */
+public class JzvdStd extends Jzvd {
+
+ public static long LAST_GET_BATTERYLEVEL_TIME = 0;
+ public static int LAST_GET_BATTERYLEVEL_PERCENT = 70;
+ protected static Timer DISMISS_CONTROL_VIEW_TIMER;
+
+ public ImageView backButton;
+ public ProgressBar bottomProgressBar, loadingProgressBar;
+ public TextView titleTextView;
+ public ImageView posterImageView;
+ public ImageView tinyBackImageView;
+ public LinearLayout batteryTimeLayout;
+ public ImageView batteryLevel;
+ public TextView videoCurrentTime;
+ public TextView replayTextView;
+ public TextView clarity;
+ public PopupWindow clarityPopWindow;
+ public TextView mRetryBtn;
+ public LinearLayout mRetryLayout;
+ public BroadcastReceiver battertReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+ int level = intent.getIntExtra("level", 0);
+ int scale = intent.getIntExtra("scale", 100);
+ int percent = level * 100 / scale;
+ LAST_GET_BATTERYLEVEL_PERCENT = percent;
+ setBatteryLevel();
+ try {
+ jzvdContext.unregisterReceiver(battertReceiver);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ };
+ protected DismissControlViewTimerTask mDismissControlViewTimerTask;
+ protected Dialog mProgressDialog;
+ protected ProgressBar mDialogProgressBar;
+ protected TextView mDialogSeekTime;
+ protected TextView mDialogTotalTime;
+ protected ImageView mDialogIcon;
+ protected Dialog mVolumeDialog;
+ protected ProgressBar mDialogVolumeProgressBar;
+ protected TextView mDialogVolumeTextView;
+ protected ImageView mDialogVolumeImageView;
+ protected Dialog mBrightnessDialog;
+ protected ProgressBar mDialogBrightnessProgressBar;
+ protected TextView mDialogBrightnessTextView;
+ protected boolean mIsWifi;
+ public BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ boolean isWifi = JZUtils.isWifiConnected(context);
+ if (mIsWifi == isWifi) return;
+ mIsWifi = isWifi;
+ if (!mIsWifi && !WIFI_TIP_DIALOG_SHOWED && state == STATE_PLAYING) {
+ startButton.performClick();
+ showWifiDialog();
+ }
+ }
+ }
+ };
+ protected ArrayDeque delayTask = new ArrayDeque<>();
+
+ public JzvdStd(Context context) {
+ super(context);
+ }
+
+ public JzvdStd(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void init(Context context) {
+ super.init(context);
+ batteryTimeLayout = findViewById(R.id.battery_time_layout);
+ bottomProgressBar = findViewById(R.id.bottom_progress);
+ titleTextView = findViewById(R.id.title);
+ backButton = findViewById(R.id.back);
+ posterImageView = findViewById(R.id.poster);
+ loadingProgressBar = findViewById(R.id.loading);
+ tinyBackImageView = findViewById(R.id.back_tiny);
+ batteryLevel = findViewById(R.id.battery_level);
+ videoCurrentTime = findViewById(R.id.video_current_time);
+ replayTextView = findViewById(R.id.replay_text);
+ clarity = findViewById(R.id.clarity);
+ mRetryBtn = findViewById(R.id.retry_btn);
+ mRetryLayout = findViewById(R.id.retry_layout);
+
+ if (batteryTimeLayout == null) {
+ batteryTimeLayout = new LinearLayout(context);
+ }
+ if (bottomProgressBar == null) {
+ bottomProgressBar = new ProgressBar(context);
+ }
+ if (titleTextView == null) {
+ titleTextView = new TextView(context);
+ }
+ if (backButton == null) {
+ backButton = new ImageView(context);
+ }
+ if (posterImageView == null) {
+ posterImageView = new ImageView(context);
+ }
+ if (loadingProgressBar == null) {
+ loadingProgressBar = new ProgressBar(context);
+ }
+ if (tinyBackImageView == null) {
+ tinyBackImageView = new ImageView(context);
+ }
+ if (batteryLevel == null) {
+ batteryLevel = new ImageView(context);
+ }
+ if (videoCurrentTime == null) {
+ videoCurrentTime = new TextView(context);
+ }
+ if (replayTextView == null) {
+ replayTextView = new TextView(context);
+ }
+ if (clarity == null) {
+ clarity = new TextView(context);
+ }
+ if (mRetryBtn == null) {
+ mRetryBtn = new TextView(context);
+ }
+ if (mRetryLayout == null) {
+ mRetryLayout = new LinearLayout(context);
+ }
+
+ posterImageView.setOnClickListener(this);
+ backButton.setOnClickListener(this);
+ tinyBackImageView.setOnClickListener(this);
+ clarity.setOnClickListener(this);
+ mRetryBtn.setOnClickListener(this);
+ }
+
+ public void setUp(JZDataSource jzDataSource, int screen, Class mediaInterfaceClass) {
+ if ((System.currentTimeMillis() - gobakFullscreenTime) < 200) {
+ return;
+ }
+
+ if ((System.currentTimeMillis() - gotoFullscreenTime) < 200) {
+ return;
+ }
+
+
+ super.setUp(jzDataSource, screen, mediaInterfaceClass);
+ titleTextView.setText(jzDataSource.title);
+ setScreen(screen);
+ }
+
+ @Override
+ public void changeUrl(JZDataSource jzDataSource, long seekToInAdvance) {
+ super.changeUrl(jzDataSource, seekToInAdvance);
+ titleTextView.setText(jzDataSource.title);
+ }
+
+ public void changeStartButtonSize(int size) {
+ ViewGroup.LayoutParams lp = startButton.getLayoutParams();
+ lp.height = size;
+ lp.width = size;
+ lp = loadingProgressBar.getLayoutParams();
+ lp.height = size;
+ lp.width = size;
+ }
+
+ @Override
+ public int getLayoutId() {
+ return R.layout.jz_layout_std;
+ }
+
+ @Override
+ public void onStateNormal() {
+ super.onStateNormal();
+ changeUiToNormal();
+ }
+
+ @Override
+ public void onStatePreparing() {
+ super.onStatePreparing();
+ changeUiToPreparing();
+ }
+
+ public void onStatePreparingPlaying() {
+ super.onStatePreparingPlaying();
+ changeUIToPreparingPlaying();
+ }
+
+ public void onStatePreparingChangeUrl() {
+ super.onStatePreparingChangeUrl();
+ changeUIToPreparingChangeUrl();
+ }
+
+ @Override
+ public void onStatePlaying() {
+ super.onStatePlaying();
+ changeUiToPlayingClear();
+ }
+
+ @Override
+ public void onStatePause() {
+ super.onStatePause();
+ changeUiToPauseShow();
+ cancelDismissControlViewTimer();
+ }
+
+ @Override
+ public void onStateError() {
+ super.onStateError();
+ changeUiToError();
+ }
+
+ @Override
+ public void onStateAutoComplete() {
+ super.onStateAutoComplete();
+ changeUiToComplete();
+ cancelDismissControlViewTimer();
+ bottomProgressBar.setProgress(100);
+ }
+
+ @Override
+ public void startVideo() {
+ super.startVideo();
+ registerWifiListener(getApplicationContext());
+ }
+
+ /**
+ * 双击
+ */
+ protected GestureDetector gestureDetector = new GestureDetector(getContext().getApplicationContext(), new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ if (state == STATE_PLAYING || state == STATE_PAUSE) {
+ Log.d(TAG, "doublClick [" + this.hashCode() + "] ");
+ startButton.performClick();
+ }
+ return super.onDoubleTap(e);
+ }
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ if (!mChangePosition && !mChangeVolume) {
+ onClickUiToggle();
+ }
+ return super.onSingleTapConfirmed(e);
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e) {
+ super.onLongPress(e);
+ }
+ });
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ int id = v.getId();
+ if (id == R.id.surface_container) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ break;
+ case MotionEvent.ACTION_UP:
+ startDismissControlViewTimer();
+ if (mChangePosition) {
+ long duration = getDuration();
+ int progress = (int) (mSeekTimePosition * 100 / (duration == 0 ? 1 : duration));
+ bottomProgressBar.setProgress(progress);
+ }
+ break;
+ }
+ gestureDetector.onTouchEvent(event);
+ } else if (id == R.id.bottom_seek_progress) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ cancelDismissControlViewTimer();
+ break;
+ case MotionEvent.ACTION_UP:
+ startDismissControlViewTimer();
+ break;
+ }
+ }
+ return super.onTouch(v, event);
+ }
+
+ @Override
+ public void onClick(View v) {
+ super.onClick(v);
+ int i = v.getId();
+ if (i == R.id.poster) {
+ clickPoster();
+ } else if (i == R.id.surface_container) {
+ clickSurfaceContainer();
+ if (clarityPopWindow != null) {
+ clarityPopWindow.dismiss();
+ }
+ } else if (i == R.id.back) {
+ clickBack();
+ } else if (i == R.id.back_tiny) {
+ clickBackTiny();
+ } else if (i == R.id.clarity) {
+ clickClarity();
+ } else if (i == R.id.retry_btn) {
+ clickRetryBtn();
+ }
+ }
+
+ protected void clickRetryBtn() {
+ if (jzDataSource.urlsMap.isEmpty() || jzDataSource.getCurrentUrl() == null) {
+ Toast.makeText(jzvdContext, getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show();
+ return;
+ }
+ if (!jzDataSource.getCurrentUrl().toString().startsWith("file") && !
+ jzDataSource.getCurrentUrl().toString().startsWith("/") &&
+ !JZUtils.isWifiConnected(jzvdContext) && !WIFI_TIP_DIALOG_SHOWED) {
+ showWifiDialog();
+ return;
+ }
+ seekToInAdvance = mCurrentPosition;
+ startVideo();
+ }
+
+ protected void clickClarity() {
+ onCLickUiToggleToClear();
+
+ LayoutInflater inflater = (LayoutInflater) jzvdContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ final LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.jz_layout_clarity, null);
+
+ OnClickListener mQualityListener = v1 -> {
+ int index = (int) v1.getTag();
+
+// this.seekToInAdvance = getCurrentPositionWhenPlaying();
+ jzDataSource.currentUrlIndex = index;
+// onStatePreparingChangeUrl();
+
+ changeUrl(jzDataSource, getCurrentPositionWhenPlaying());
+
+ clarity.setText(jzDataSource.getCurrentKey().toString());
+ for (int j = 0; j < layout.getChildCount(); j++) {//设置点击之后的颜色
+ if (j == jzDataSource.currentUrlIndex) {
+ ((TextView) layout.getChildAt(j)).setTextColor(Color.parseColor("#fff85959"));
+ } else {
+ ((TextView) layout.getChildAt(j)).setTextColor(Color.parseColor("#ffffff"));
+ }
+ }
+ if (clarityPopWindow != null) {
+ clarityPopWindow.dismiss();
+ }
+ };
+
+ for (int j = 0; j < jzDataSource.urlsMap.size(); j++) {
+ String key = jzDataSource.getKeyFromDataSource(j);
+ TextView clarityItem = (TextView) View.inflate(jzvdContext, R.layout.jz_layout_clarity_item, null);
+ clarityItem.setText(key);
+ clarityItem.setTag(j);
+ layout.addView(clarityItem, j);
+ clarityItem.setOnClickListener(mQualityListener);
+ if (j == jzDataSource.currentUrlIndex) {
+ clarityItem.setTextColor(Color.parseColor("#fff85959"));
+ }
+ }
+
+ clarityPopWindow = new PopupWindow(layout, JZUtils.dip2px(jzvdContext, 240), LayoutParams.MATCH_PARENT, true);
+ clarityPopWindow.setContentView(layout);
+ clarityPopWindow.setAnimationStyle(R.style.pop_animation);
+ clarityPopWindow.showAtLocation(textureViewContainer, Gravity.END, 0, 0);
+// int offsetX = clarity.getMeasuredWidth() / 3;
+// int offsetY = clarity.getMeasuredHeight() / 3;
+// clarityPopWindow.update(clarity, -offsetX, -offsetY, Math.round(layout.getMeasuredWidth() * 2), layout.getMeasuredHeight());
+ }
+
+ protected void clickBackTiny() {
+ clearFloatScreen();
+ }
+
+ protected void clickBack() {
+ backPress();
+ }
+
+ protected void clickSurfaceContainer() {
+ startDismissControlViewTimer();
+ }
+
+ protected void clickPoster() {
+ if (jzDataSource == null || jzDataSource.urlsMap.isEmpty() || jzDataSource.getCurrentUrl() == null) {
+ Toast.makeText(jzvdContext, getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show();
+ return;
+ }
+ if (state == STATE_NORMAL) {
+ if (!jzDataSource.getCurrentUrl().toString().startsWith("file") &&
+ !jzDataSource.getCurrentUrl().toString().startsWith("/") &&
+ !JZUtils.isWifiConnected(jzvdContext) && !WIFI_TIP_DIALOG_SHOWED) {
+ showWifiDialog();
+ return;
+ }
+ startVideo();
+ } else if (state == STATE_AUTO_COMPLETE) {
+ onClickUiToggle();
+ }
+ }
+
+ @Override
+ public void setScreenNormal() {
+ super.setScreenNormal();
+ fullscreenButton.setImageResource(R.drawable.jz_enlarge);
+ backButton.setVisibility(View.GONE);
+ tinyBackImageView.setVisibility(View.INVISIBLE);
+ changeStartButtonSize((int) getResources().getDimension(R.dimen.jz_start_button_w_h_normal));
+ batteryTimeLayout.setVisibility(View.GONE);
+ clarity.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void setScreenFullscreen() {
+ super.setScreenFullscreen();
+ //进入全屏之后要保证原来的播放状态和ui状态不变,改变个别的ui
+ fullscreenButton.setImageResource(R.drawable.jz_shrink);
+ backButton.setVisibility(View.VISIBLE);
+ tinyBackImageView.setVisibility(View.INVISIBLE);
+ batteryTimeLayout.setVisibility(View.VISIBLE);
+ if (jzDataSource.urlsMap.size() == 1) {
+ clarity.setVisibility(GONE);
+ } else {
+ clarity.setText(jzDataSource.getCurrentKey().toString());
+ clarity.setVisibility(View.VISIBLE);
+ }
+ changeStartButtonSize((int) getResources().getDimension(R.dimen.jz_start_button_w_h_fullscreen));
+ setSystemTimeAndBattery();
+ }
+
+ @Override
+ public void setScreenTiny() {
+ super.setScreenTiny();
+ tinyBackImageView.setVisibility(View.VISIBLE);
+ setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
+ batteryTimeLayout.setVisibility(View.GONE);
+ clarity.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void showWifiDialog() {
+ super.showWifiDialog();
+ AlertDialog.Builder builder = new AlertDialog.Builder(jzvdContext);
+ builder.setMessage(getResources().getString(R.string.tips_not_wifi));
+ builder.setPositiveButton(getResources().getString(R.string.tips_not_wifi_confirm), (dialog, which) -> {
+ dialog.dismiss();
+ WIFI_TIP_DIALOG_SHOWED = true;
+ if (state == STATE_PAUSE) {
+ startButton.performClick();
+ } else {
+ startVideo();
+ }
+
+ });
+ builder.setNegativeButton(getResources().getString(R.string.tips_not_wifi_cancel), (dialog, which) -> {
+ dialog.dismiss();
+ releaseAllVideos();
+ clearFloatScreen();
+ });
+ builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ dialog.dismiss();
+ releaseAllVideos();
+ clearFloatScreen();
+ }
+ });
+
+ builder.create().show();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ super.onStartTrackingTouch(seekBar);
+ cancelDismissControlViewTimer();
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ super.onStopTrackingTouch(seekBar);
+ startDismissControlViewTimer();
+ }
+
+ public void onClickUiToggle() {//这是事件
+ if (bottomContainer.getVisibility() != View.VISIBLE) {
+ setSystemTimeAndBattery();
+ clarity.setText(jzDataSource.getCurrentKey().toString());
+ }
+ if (state == STATE_PREPARING) {
+ changeUiToPreparing();
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ } else {
+ setSystemTimeAndBattery();
+ }
+ } else if (state == STATE_PLAYING) {
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ changeUiToPlayingClear();
+ } else {
+ changeUiToPlayingShow();
+ }
+ } else if (state == STATE_PAUSE) {
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ changeUiToPauseClear();
+ } else {
+ changeUiToPauseShow();
+ }
+ }
+ }
+
+ public void setSystemTimeAndBattery() {
+ SimpleDateFormat dateFormater = new SimpleDateFormat("HH:mm");
+ Date date = new Date();
+ videoCurrentTime.setText(dateFormater.format(date));
+ if ((System.currentTimeMillis() - LAST_GET_BATTERYLEVEL_TIME) > 30000) {
+ LAST_GET_BATTERYLEVEL_TIME = System.currentTimeMillis();
+ jzvdContext.registerReceiver(
+ battertReceiver,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED)
+ );
+ } else {
+ setBatteryLevel();
+ }
+ }
+
+ public void setBatteryLevel() {
+ int percent = LAST_GET_BATTERYLEVEL_PERCENT;
+ if (percent < 15) {
+ batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_10);
+ } else if (percent >= 15 && percent < 40) {
+ batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_30);
+ } else if (percent >= 40 && percent < 60) {
+ batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_50);
+ } else if (percent >= 60 && percent < 80) {
+ batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_70);
+ } else if (percent >= 80 && percent < 95) {
+ batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_90);
+ } else if (percent >= 95 && percent <= 100) {
+ batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_100);
+ }
+ }
+
+ //** 和onClickUiToggle重复,要干掉
+ public void onCLickUiToggleToClear() {
+ if (state == STATE_PREPARING) {
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ changeUiToPreparing();
+ } else {
+ }
+ } else if (state == STATE_PLAYING) {
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ changeUiToPlayingClear();
+ } else {
+ }
+ } else if (state == STATE_PAUSE) {
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ changeUiToPauseClear();
+ } else {
+ }
+ } else if (state == STATE_AUTO_COMPLETE) {
+ if (bottomContainer.getVisibility() == View.VISIBLE) {
+ changeUiToComplete();
+ } else {
+ }
+ }
+ }
+
+ @Override
+ public void onProgress(int progress, long position, long duration) {
+ super.onProgress(progress, position, duration);
+ if (progress != 0) bottomProgressBar.setProgress(progress);
+ }
+
+ @Override
+ public void setBufferProgress(int bufferProgress) {
+ super.setBufferProgress(bufferProgress);
+ if (bufferProgress != 0) bottomProgressBar.setSecondaryProgress(bufferProgress);
+ }
+
+ @Override
+ public void resetProgressAndTime() {
+ super.resetProgressAndTime();
+ bottomProgressBar.setProgress(0);
+ bottomProgressBar.setSecondaryProgress(0);
+ }
+
+ public void changeUiToNormal() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE,
+ View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+ }
+
+ public void changeUiToPreparing() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
+ View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+ }
+
+ public void changeUIToPreparingPlaying() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.INVISIBLE,
+ View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+ }
+
+ public void changeUIToPreparingChangeUrl() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
+ View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+ }
+
+ public void changeUiToPlayingShow() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.VISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+
+ }
+
+ public void changeUiToPlayingClear() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE);
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+
+ }
+
+ public void changeUiToPauseShow() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.VISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+ }
+
+ public void changeUiToPauseClear() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE);
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+
+ }
+
+ public void changeUiToComplete() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE,
+ View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+
+ }
+
+ public void changeUiToError() {
+ switch (screen) {
+ case SCREEN_NORMAL:
+ setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.VISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_FULLSCREEN:
+ setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE,
+ View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE);
+ updateStartImage();
+ break;
+ case SCREEN_TINY:
+ break;
+ }
+
+ }
+
+ public void setAllControlsVisiblity(int topCon, int bottomCon, int startBtn, int loadingPro,
+ int posterImg, int bottomPro, int retryLayout) {
+ topContainer.setVisibility(topCon);
+ bottomContainer.setVisibility(bottomCon);
+ startButton.setVisibility(startBtn);
+ loadingProgressBar.setVisibility(loadingPro);
+ posterImageView.setVisibility(posterImg);
+ bottomProgressBar.setVisibility(bottomPro);
+ mRetryLayout.setVisibility(retryLayout);
+ }
+
+ public void updateStartImage() {
+ if (state == STATE_PLAYING) {
+ startButton.setVisibility(VISIBLE);
+ startButton.setImageResource(R.drawable.jz_click_pause_selector);
+ replayTextView.setVisibility(GONE);
+ } else if (state == STATE_ERROR) {
+ startButton.setVisibility(INVISIBLE);
+ replayTextView.setVisibility(GONE);
+ } else if (state == STATE_AUTO_COMPLETE) {
+ startButton.setVisibility(VISIBLE);
+ startButton.setImageResource(R.drawable.jz_click_replay_selector);
+ replayTextView.setVisibility(VISIBLE);
+ } else {
+ startButton.setImageResource(R.drawable.jz_click_play_selector);
+ replayTextView.setVisibility(GONE);
+ }
+ }
+
+ @Override
+ public void showProgressDialog(float deltaX, String seekTime, long seekTimePosition, String totalTime, long totalTimeDuration) {
+ super.showProgressDialog(deltaX, seekTime, seekTimePosition, totalTime, totalTimeDuration);
+ if (mProgressDialog == null) {
+ View localView = LayoutInflater.from(jzvdContext).inflate(R.layout.jz_dialog_progress, null);
+ mDialogProgressBar = localView.findViewById(R.id.duration_progressbar);
+ mDialogSeekTime = localView.findViewById(R.id.tv_current);
+ mDialogTotalTime = localView.findViewById(R.id.tv_duration);
+ mDialogIcon = localView.findViewById(R.id.duration_image_tip);
+ mProgressDialog = createDialogWithView(localView);
+ }
+ if (!mProgressDialog.isShowing()) {
+ mProgressDialog.show();
+ }
+
+ mDialogSeekTime.setText(seekTime);
+ mDialogTotalTime.setText(" / " + totalTime);
+ mDialogProgressBar.setProgress(totalTimeDuration <= 0 ? 0 : (int) (seekTimePosition * 100 / totalTimeDuration));
+ if (deltaX > 0) {
+ mDialogIcon.setBackgroundResource(R.drawable.jz_forward_icon);
+ } else {
+ mDialogIcon.setBackgroundResource(R.drawable.jz_backward_icon);
+ }
+ onCLickUiToggleToClear();
+ }
+
+ @Override
+ public void dismissProgressDialog() {
+ super.dismissProgressDialog();
+ if (mProgressDialog != null) {
+ mProgressDialog.dismiss();
+ }
+ }
+
+ @Override
+ public void showVolumeDialog(float deltaY, int volumePercent) {
+ super.showVolumeDialog(deltaY, volumePercent);
+ if (mVolumeDialog == null) {
+ View localView = LayoutInflater.from(jzvdContext).inflate(R.layout.jz_dialog_volume, null);
+ mDialogVolumeImageView = localView.findViewById(R.id.volume_image_tip);
+ mDialogVolumeTextView = localView.findViewById(R.id.tv_volume);
+ mDialogVolumeProgressBar = localView.findViewById(R.id.volume_progressbar);
+ mVolumeDialog = createDialogWithView(localView);
+ }
+ if (!mVolumeDialog.isShowing()) {
+ mVolumeDialog.show();
+ }
+ if (volumePercent <= 0) {
+ mDialogVolumeImageView.setBackgroundResource(R.drawable.jz_close_volume);
+ } else {
+ mDialogVolumeImageView.setBackgroundResource(R.drawable.jz_add_volume);
+ }
+ if (volumePercent > 100) {
+ volumePercent = 100;
+ } else if (volumePercent < 0) {
+ volumePercent = 0;
+ }
+ mDialogVolumeTextView.setText(volumePercent + "%");
+ mDialogVolumeProgressBar.setProgress(volumePercent);
+ onCLickUiToggleToClear();
+ }
+
+ @Override
+ public void dismissVolumeDialog() {
+ super.dismissVolumeDialog();
+ if (mVolumeDialog != null) {
+ mVolumeDialog.dismiss();
+ }
+ }
+
+ @Override
+ public void showBrightnessDialog(int brightnessPercent) {
+ super.showBrightnessDialog(brightnessPercent);
+ if (mBrightnessDialog == null) {
+ View localView = LayoutInflater.from(jzvdContext).inflate(R.layout.jz_dialog_brightness, null);
+ mDialogBrightnessTextView = localView.findViewById(R.id.tv_brightness);
+ mDialogBrightnessProgressBar = localView.findViewById(R.id.brightness_progressbar);
+ mBrightnessDialog = createDialogWithView(localView);
+ }
+ if (!mBrightnessDialog.isShowing()) {
+ mBrightnessDialog.show();
+ }
+ if (brightnessPercent > 100) {
+ brightnessPercent = 100;
+ } else if (brightnessPercent < 0) {
+ brightnessPercent = 0;
+ }
+ mDialogBrightnessTextView.setText(brightnessPercent + "%");
+ mDialogBrightnessProgressBar.setProgress(brightnessPercent);
+ onCLickUiToggleToClear();
+ }
+
+ @Override
+ public void dismissBrightnessDialog() {
+ super.dismissBrightnessDialog();
+ if (mBrightnessDialog != null) {
+ mBrightnessDialog.dismiss();
+ }
+ }
+
+ public Dialog createDialogWithView(View localView) {
+ Dialog dialog = new Dialog(jzvdContext, R.style.jz_style_dialog_progress);
+ dialog.setContentView(localView);
+ Window window = dialog.getWindow();
+ window.addFlags(Window.FEATURE_ACTION_BAR);
+ window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ window.setLayout(-2, -2);
+ WindowManager.LayoutParams localLayoutParams = window.getAttributes();
+ localLayoutParams.gravity = Gravity.CENTER;
+ window.setAttributes(localLayoutParams);
+ return dialog;
+ }
+
+ public void startDismissControlViewTimer() {
+ cancelDismissControlViewTimer();
+ DISMISS_CONTROL_VIEW_TIMER = new Timer();
+ mDismissControlViewTimerTask = new DismissControlViewTimerTask();
+ DISMISS_CONTROL_VIEW_TIMER.schedule(mDismissControlViewTimerTask, 2500);
+ }
+
+ public void cancelDismissControlViewTimer() {
+ if (DISMISS_CONTROL_VIEW_TIMER != null) {
+ DISMISS_CONTROL_VIEW_TIMER.cancel();
+ }
+ if (mDismissControlViewTimerTask != null) {
+ mDismissControlViewTimerTask.cancel();
+ }
+
+ }
+
+ @Override
+ public void onCompletion() {
+ super.onCompletion();
+ cancelDismissControlViewTimer();
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ cancelDismissControlViewTimer();
+ unregisterWifiListener(getApplicationContext());
+ }
+
+ public void dissmissControlView() {
+ if (state != STATE_NORMAL
+ && state != STATE_ERROR
+ && state != STATE_AUTO_COMPLETE) {
+ post(() -> {
+ bottomContainer.setVisibility(View.INVISIBLE);
+ topContainer.setVisibility(View.INVISIBLE);
+ startButton.setVisibility(View.INVISIBLE);
+
+ if (screen != SCREEN_TINY) {
+ bottomProgressBar.setVisibility(View.VISIBLE);
+ }
+ cancelProgressTimer();
+ });
+ }
+ }
+
+ public void registerWifiListener(Context context) {
+ if (context == null) return;
+ mIsWifi = JZUtils.isWifiConnected(context);
+ IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+ context.registerReceiver(wifiReceiver, intentFilter);
+ }
+
+ public void unregisterWifiListener(Context context) {
+ if (context == null) return;
+ try {
+ context.unregisterReceiver(wifiReceiver);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public class DismissControlViewTimerTask extends TimerTask {
+
+ @Override
+ public void run() {
+ dissmissControlView();
+ }
+ }
+
+}
diff --git a/library/src/main/java/org/jzvd/jzvideo/JZVideoA.kt b/library/src/main/java/org/jzvd/jzvideo/JZVideoA.kt
new file mode 100644
index 0000000..bdb5e4b
--- /dev/null
+++ b/library/src/main/java/org/jzvd/jzvideo/JZVideoA.kt
@@ -0,0 +1,37 @@
+package org.jzvd.jzvideo
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.RelativeLayout
+
+const val TAG = "JZVD"
+
+
+open class JZVideoA : RelativeLayout {
+
+ enum class State {
+ IDLE, NORMAL, PREPARING, PREPARING_CHANGE_URL, PREPARING_PLAYING,
+ PREPARED, PLAYING, PAUSE, COMPLETE, ERROR
+ }
+
+ enum class Screen {
+ NORMAL, FULLSCREEN, TINY
+ }
+
+ lateinit var state: State
+
+
+ constructor(ctx: Context) : super(ctx) {
+ }
+
+ constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
+ }
+
+ companion object {
+ @JvmStatic
+ fun releaseAllVideos() {
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/library/src/main/res/anim/pop_from_bottom_anim_in.xml b/library/src/main/res/anim/pop_from_bottom_anim_in.xml
new file mode 100644
index 0000000..7536a52
--- /dev/null
+++ b/library/src/main/res/anim/pop_from_bottom_anim_in.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/library/src/main/res/anim/pop_from_bottom_anim_out.xml b/library/src/main/res/anim/pop_from_bottom_anim_out.xml
new file mode 100644
index 0000000..1ee5add
--- /dev/null
+++ b/library/src/main/res/anim/pop_from_bottom_anim_out.xml
@@ -0,0 +1,5 @@
+
+
diff --git a/library/src/main/res/drawable-xhdpi/jz_add_volume.png b/library/src/main/res/drawable-xhdpi/jz_add_volume.png
new file mode 100644
index 0000000..868b308
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_add_volume.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_back_normal.png b/library/src/main/res/drawable-xhdpi/jz_back_normal.png
new file mode 100644
index 0000000..8b58353
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_back_normal.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_back_pressed.png b/library/src/main/res/drawable-xhdpi/jz_back_pressed.png
new file mode 100644
index 0000000..82d2ba6
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_back_pressed.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_back_tiny_normal.png b/library/src/main/res/drawable-xhdpi/jz_back_tiny_normal.png
new file mode 100644
index 0000000..e6ca6f4
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_back_tiny_normal.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_back_tiny_pressed.png b/library/src/main/res/drawable-xhdpi/jz_back_tiny_pressed.png
new file mode 100644
index 0000000..2ca8252
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_back_tiny_pressed.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_backward_icon.png b/library/src/main/res/drawable-xhdpi/jz_backward_icon.png
new file mode 100644
index 0000000..51f5ca3
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_backward_icon.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_battery_level_10.png b/library/src/main/res/drawable-xhdpi/jz_battery_level_10.png
new file mode 100644
index 0000000..1d5b5f6
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_battery_level_10.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_battery_level_100.png b/library/src/main/res/drawable-xhdpi/jz_battery_level_100.png
new file mode 100644
index 0000000..6f0cf51
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_battery_level_100.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_battery_level_30.png b/library/src/main/res/drawable-xhdpi/jz_battery_level_30.png
new file mode 100644
index 0000000..947e905
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_battery_level_30.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_battery_level_50.png b/library/src/main/res/drawable-xhdpi/jz_battery_level_50.png
new file mode 100644
index 0000000..e4c75ff
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_battery_level_50.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_battery_level_70.png b/library/src/main/res/drawable-xhdpi/jz_battery_level_70.png
new file mode 100644
index 0000000..25177bf
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_battery_level_70.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_battery_level_90.png b/library/src/main/res/drawable-xhdpi/jz_battery_level_90.png
new file mode 100644
index 0000000..6c681c5
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_battery_level_90.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_brightness_video.png b/library/src/main/res/drawable-xhdpi/jz_brightness_video.png
new file mode 100644
index 0000000..df25316
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_brightness_video.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_clarity_popwindow_bg.9.png b/library/src/main/res/drawable-xhdpi/jz_clarity_popwindow_bg.9.png
new file mode 100644
index 0000000..c5f67fd
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_clarity_popwindow_bg.9.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_close_volume.png b/library/src/main/res/drawable-xhdpi/jz_close_volume.png
new file mode 100644
index 0000000..1e08431
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_close_volume.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_enlarge.png b/library/src/main/res/drawable-xhdpi/jz_enlarge.png
new file mode 100644
index 0000000..bf69e8b
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_enlarge.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_forward_icon.png b/library/src/main/res/drawable-xhdpi/jz_forward_icon.png
new file mode 100644
index 0000000..f7e3188
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_forward_icon.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_loading_bg.png b/library/src/main/res/drawable-xhdpi/jz_loading_bg.png
new file mode 100644
index 0000000..b85c037
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_loading_bg.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_pause_normal.png b/library/src/main/res/drawable-xhdpi/jz_pause_normal.png
new file mode 100644
index 0000000..12b158e
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_pause_normal.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_pause_pressed.png b/library/src/main/res/drawable-xhdpi/jz_pause_pressed.png
new file mode 100644
index 0000000..3a2f8a3
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_pause_pressed.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_play_normal.png b/library/src/main/res/drawable-xhdpi/jz_play_normal.png
new file mode 100644
index 0000000..74db6df
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_play_normal.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_play_pressed.png b/library/src/main/res/drawable-xhdpi/jz_play_pressed.png
new file mode 100644
index 0000000..3aaa183
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_play_pressed.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_restart_normal.png b/library/src/main/res/drawable-xhdpi/jz_restart_normal.png
new file mode 100644
index 0000000..618616e
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_restart_normal.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_restart_pressed.png b/library/src/main/res/drawable-xhdpi/jz_restart_pressed.png
new file mode 100644
index 0000000..21d4632
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_restart_pressed.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_share_normal.png b/library/src/main/res/drawable-xhdpi/jz_share_normal.png
new file mode 100644
index 0000000..73d62e1
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_share_normal.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_share_pressed.png b/library/src/main/res/drawable-xhdpi/jz_share_pressed.png
new file mode 100644
index 0000000..e899314
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_share_pressed.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_shrink.png b/library/src/main/res/drawable-xhdpi/jz_shrink.png
new file mode 100644
index 0000000..70bb00c
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_shrink.png differ
diff --git a/library/src/main/res/drawable-xhdpi/jz_volume_icon.png b/library/src/main/res/drawable-xhdpi/jz_volume_icon.png
new file mode 100644
index 0000000..deb5358
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/jz_volume_icon.png differ
diff --git a/library/src/main/res/drawable/jz_bottom_bg.9.png b/library/src/main/res/drawable/jz_bottom_bg.9.png
new file mode 100644
index 0000000..48a5b47
Binary files /dev/null and b/library/src/main/res/drawable/jz_bottom_bg.9.png differ
diff --git a/library/src/main/res/drawable/jz_bottom_progress.xml b/library/src/main/res/drawable/jz_bottom_progress.xml
new file mode 100644
index 0000000..5db2949
--- /dev/null
+++ b/library/src/main/res/drawable/jz_bottom_progress.xml
@@ -0,0 +1,28 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_bottom_seek_poster.xml b/library/src/main/res/drawable/jz_bottom_seek_poster.xml
new file mode 100644
index 0000000..0cd8f9b
--- /dev/null
+++ b/library/src/main/res/drawable/jz_bottom_seek_poster.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_bottom_seek_progress.xml b/library/src/main/res/drawable/jz_bottom_seek_progress.xml
new file mode 100644
index 0000000..212fccc
--- /dev/null
+++ b/library/src/main/res/drawable/jz_bottom_seek_progress.xml
@@ -0,0 +1,28 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_clarity_popwindow_bg.9.png b/library/src/main/res/drawable/jz_clarity_popwindow_bg.9.png
new file mode 100644
index 0000000..3bb3053
Binary files /dev/null and b/library/src/main/res/drawable/jz_clarity_popwindow_bg.9.png differ
diff --git a/library/src/main/res/drawable/jz_click_back_selector.xml b/library/src/main/res/drawable/jz_click_back_selector.xml
new file mode 100644
index 0000000..5379ed6
--- /dev/null
+++ b/library/src/main/res/drawable/jz_click_back_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_click_back_tiny_selector.xml b/library/src/main/res/drawable/jz_click_back_tiny_selector.xml
new file mode 100644
index 0000000..baca67f
--- /dev/null
+++ b/library/src/main/res/drawable/jz_click_back_tiny_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_click_pause_selector.xml b/library/src/main/res/drawable/jz_click_pause_selector.xml
new file mode 100644
index 0000000..93559b8
--- /dev/null
+++ b/library/src/main/res/drawable/jz_click_pause_selector.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_click_play_selector.xml b/library/src/main/res/drawable/jz_click_play_selector.xml
new file mode 100644
index 0000000..e99799c
--- /dev/null
+++ b/library/src/main/res/drawable/jz_click_play_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_click_replay_selector.xml b/library/src/main/res/drawable/jz_click_replay_selector.xml
new file mode 100644
index 0000000..9b5ca8c
--- /dev/null
+++ b/library/src/main/res/drawable/jz_click_replay_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_click_share_selector.xml b/library/src/main/res/drawable/jz_click_share_selector.xml
new file mode 100644
index 0000000..0de0b6f
--- /dev/null
+++ b/library/src/main/res/drawable/jz_click_share_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_dialog_progress.xml b/library/src/main/res/drawable/jz_dialog_progress.xml
new file mode 100644
index 0000000..35179bd
--- /dev/null
+++ b/library/src/main/res/drawable/jz_dialog_progress.xml
@@ -0,0 +1,17 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_dialog_progress_bg.xml b/library/src/main/res/drawable/jz_dialog_progress_bg.xml
new file mode 100644
index 0000000..421a56c
--- /dev/null
+++ b/library/src/main/res/drawable/jz_dialog_progress_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/drawable/jz_loading.xml b/library/src/main/res/drawable/jz_loading.xml
new file mode 100644
index 0000000..9eaf8e0
--- /dev/null
+++ b/library/src/main/res/drawable/jz_loading.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/library/src/main/res/drawable/jz_retry.xml b/library/src/main/res/drawable/jz_retry.xml
new file mode 100644
index 0000000..76c211a
--- /dev/null
+++ b/library/src/main/res/drawable/jz_retry.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/drawable/jz_seek_poster_normal.xml b/library/src/main/res/drawable/jz_seek_poster_normal.xml
new file mode 100644
index 0000000..e928712
--- /dev/null
+++ b/library/src/main/res/drawable/jz_seek_poster_normal.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_seek_poster_pressed.xml b/library/src/main/res/drawable/jz_seek_poster_pressed.xml
new file mode 100644
index 0000000..14e409a
--- /dev/null
+++ b/library/src/main/res/drawable/jz_seek_poster_pressed.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/library/src/main/res/drawable/jz_title_bg.9.png b/library/src/main/res/drawable/jz_title_bg.9.png
new file mode 100644
index 0000000..5d9df27
Binary files /dev/null and b/library/src/main/res/drawable/jz_title_bg.9.png differ
diff --git a/library/src/main/res/drawable/jz_volume_progress_bg.xml b/library/src/main/res/drawable/jz_volume_progress_bg.xml
new file mode 100644
index 0000000..a388074
--- /dev/null
+++ b/library/src/main/res/drawable/jz_volume_progress_bg.xml
@@ -0,0 +1,19 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/layout/jz_dialog_brightness.xml b/library/src/main/res/layout/jz_dialog_brightness.xml
new file mode 100644
index 0000000..90c55e3
--- /dev/null
+++ b/library/src/main/res/layout/jz_dialog_brightness.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/jz_dialog_progress.xml b/library/src/main/res/layout/jz_dialog_progress.xml
new file mode 100644
index 0000000..b16b2e7
--- /dev/null
+++ b/library/src/main/res/layout/jz_dialog_progress.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/layout/jz_dialog_volume.xml b/library/src/main/res/layout/jz_dialog_volume.xml
new file mode 100644
index 0000000..5b4d2a1
--- /dev/null
+++ b/library/src/main/res/layout/jz_dialog_volume.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/jz_layout_clarity.xml b/library/src/main/res/layout/jz_layout_clarity.xml
new file mode 100644
index 0000000..3670c9d
--- /dev/null
+++ b/library/src/main/res/layout/jz_layout_clarity.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/library/src/main/res/layout/jz_layout_clarity_item.xml b/library/src/main/res/layout/jz_layout_clarity_item.xml
new file mode 100644
index 0000000..efeadea
--- /dev/null
+++ b/library/src/main/res/layout/jz_layout_clarity_item.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/jz_layout_std.xml b/library/src/main/res/layout/jz_layout_std.xml
new file mode 100644
index 0000000..3bfbd9a
--- /dev/null
+++ b/library/src/main/res/layout/jz_layout_std.xml
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/values-es/strings.xml b/library/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..66ea803
--- /dev/null
+++ b/library/src/main/res/values-es/strings.xml
@@ -0,0 +1,10 @@
+
+
+ Estás conectado a una red móvil, el reproductor utilizará tus datos si continuas
+ Reproducir
+ Cancelar
+ No hay vídeo
+ Volver a ver
+ Haga clic para volver a intentarlo
+ Error de carga de video
+
diff --git a/library/src/main/res/values-ja-rJP/strings.xml b/library/src/main/res/values-ja-rJP/strings.xml
new file mode 100644
index 0000000..0a5dfcf
--- /dev/null
+++ b/library/src/main/res/values-ja-rJP/strings.xml
@@ -0,0 +1,10 @@
+
+
+ あなたは現在、モバイルネットワークを使用しています
+ ビデオを再開する
+ ビデオを止める
+ URLエラー
+ リプレイ
+ 再度試してください
+ エラーが発生しました
+
\ No newline at end of file
diff --git a/library/src/main/res/values-ko-rKR/strings.xml b/library/src/main/res/values-ko-rKR/strings.xml
new file mode 100644
index 0000000..98b752c
--- /dev/null
+++ b/library/src/main/res/values-ko-rKR/strings.xml
@@ -0,0 +1,10 @@
+
+
+ 현재 모바일 네트워크를 사용 중이면 계속 플레이어가 트래픽을 소비합니다
+ 재생 다시 시작
+ 재생을 중지
+ 재생 주소 없음
+ 재생 다시 시작
+ 다시 시도 하십시오
+ 버퍼링 실패
+
\ No newline at end of file
diff --git a/library/src/main/res/values-pt/strings.xml b/library/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..87ebf5a
--- /dev/null
+++ b/library/src/main/res/values-pt/strings.xml
@@ -0,0 +1,10 @@
+
+
+ Você está usando a rede móvel, você deseja mesmo ver o vídeo?
+ Continuar
+ Parar
+ Sem vídeo
+ Replay
+ Clique para tentar novamente
+ O carregamento de vídeo falhou
+
diff --git a/library/src/main/res/values-tr/strings.xml b/library/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..037f81a
--- /dev/null
+++ b/library/src/main/res/values-tr/strings.xml
@@ -0,0 +1,10 @@
+
+
+ Şu anda mobil veriyi kullanıyorsunuz, yüksek veri kaybına yol açabilir
+ Devam Et
+ Durdur
+ URL Bulunamadı
+ Tekrar
+ Tekrar denemek için tıklayın
+ Video yüklenemedi
+
diff --git a/library/src/main/res/values-zh/strings.xml b/library/src/main/res/values-zh/strings.xml
new file mode 100644
index 0000000..944669c
--- /dev/null
+++ b/library/src/main/res/values-zh/strings.xml
@@ -0,0 +1,10 @@
+
+
+ 您当前正在使用移动网络,继续播放将消耗流量
+ 继续播放
+ 停止播放
+ 播放地址无效
+ 重播
+ 点击重试
+ 视频加载失败
+
diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..b6744b0
--- /dev/null
+++ b/library/src/main/res/values/dimens.xml
@@ -0,0 +1,4 @@
+
+ 45dp
+ 62dp
+
diff --git a/library/src/main/res/values/ids.xml b/library/src/main/res/values/ids.xml
new file mode 100644
index 0000000..3d0d301
--- /dev/null
+++ b/library/src/main/res/values/ids.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml
new file mode 100644
index 0000000..2c11f97
--- /dev/null
+++ b/library/src/main/res/values/strings.xml
@@ -0,0 +1,10 @@
+
+
+ You are currently using the mobile network, the player will continue to consume traffic
+ Resume
+ Stop play
+ No url
+ Replay
+ Click to try again
+ Video loading failed
+
diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml
new file mode 100644
index 0000000..86ad9af
--- /dev/null
+++ b/library/src/main/res/values/styles.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/xml/jz_network_security_config.xml b/library/src/main/res/xml/jz_network_security_config.xml
new file mode 100644
index 0000000..2439f15
--- /dev/null
+++ b/library/src/main/res/xml/jz_network_security_config.xml
@@ -0,0 +1,4 @@
+
+
+
+