infos = manager.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo info : infos) {
+ if (info.pid == pid)
+ return info.processName;
+ }
+ return "";
+ }
+
+ public static int getAppVersionCode(Context context) {
+ int versioncode = 0;
+ try {
+ // ---get the package info---
+ PackageManager pm = context.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+ versioncode = pi.versionCode;
+ } catch (Exception e) {
+ Log.e("VersionInfo", "Exception", e);
+ }
+ return versioncode;
+ }
+
+ public static void wrapTabIndicatorToTitle(TabLayout tabLayout, int externalMargin, int internalMargin) {
+ View tabStrip = tabLayout.getChildAt(0);
+ if (tabStrip instanceof ViewGroup) {
+ ViewGroup tabStripGroup = (ViewGroup) tabStrip;
+ int childCount = ((ViewGroup) tabStrip).getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View tabView = tabStripGroup.getChildAt(i);
+ //set minimum width to 0 for instead for small texts, indicator is not wrapped as expected
+ tabView.setMinimumWidth(0);
+ // set padding to 0 for wrapping indicator as title
+ tabView.setPadding(0, tabView.getPaddingTop(), 0, tabView.getPaddingBottom());
+ // setting custom margin between tabs
+ if (tabView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
+ ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) tabView.getLayoutParams();
+ if (i == 0) {
+ // left
+ setTabMargin(layoutParams, externalMargin, internalMargin);
+ } else if (i == childCount - 1) {
+ // right
+ setTabMargin(layoutParams, internalMargin, externalMargin);
+ } else {
+ // internal
+ setTabMargin(layoutParams, internalMargin, internalMargin);
+ }
+ }
+ }
+
+ tabLayout.requestLayout();
+ }
+ }
+
+ private static void setTabMargin(ViewGroup.MarginLayoutParams layoutParams, int start, int end) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ layoutParams.setMarginStart(start);
+ layoutParams.setMarginEnd(end);
+ } else {
+ layoutParams.leftMargin = start;
+ layoutParams.rightMargin = end;
+ }
+ }
+
+ public static boolean savePhotoToSDCard(Bitmap photoBitmap, String path, String photoName) {
+ boolean ret = false;
+ File dir = new File(path);
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+
+ File photoFile = new File(path, photoName + ".jpg");
+ FileOutputStream fileOutputStream = null;
+ try {
+ fileOutputStream = new FileOutputStream(photoFile);
+ if (photoBitmap != null) {
+ if (photoBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)) {
+ fileOutputStream.flush();
+ ret = true;
+ }
+ }
+ } catch (FileNotFoundException e) {
+ photoFile.delete();
+ e.printStackTrace();
+ } catch (IOException e) {
+ photoFile.delete();
+ e.printStackTrace();
+ } finally {
+ try {
+ fileOutputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return ret;
+ }
+
+ public static AVOptions createAVOptions() {
+ AVOptions options = new AVOptions();
+ // the unit of timeout is ms
+ options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
+ options.setInteger(AVOptions.KEY_LIVE_STREAMING, 0);
+// options.setString(AVOptions.KEY_COMP_DRM_KEY, "test123");
+ // 1 -> hw codec enable, 0 -> disable [recommended]
+ options.setInteger(AVOptions.KEY_MEDIACODEC, AVOptions.MEDIA_CODEC_SW_DECODE);
+ options.setInteger(AVOptions.KEY_PREFER_FORMAT, AVOptions.PREFER_FORMAT_MP4);
+ boolean disableLog = false;
+ options.setInteger(AVOptions.KEY_LOG_LEVEL, disableLog ? 5 : 0);
+ return options;
+ }
+}
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/CircleImageView.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/CircleImageView.java
new file mode 100644
index 0000000..7e02a25
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/CircleImageView.java
@@ -0,0 +1,76 @@
+
+package com.qiniu.droid.niuplayer.widget;
+
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.support.v7.widget.AppCompatImageView;
+
+public class CircleImageView extends AppCompatImageView {
+ public CircleImageView(Context context) {
+ super(context);
+ }
+
+ public CircleImageView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private Paint mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private Bitmap mRawBitmap;
+ private BitmapShader mShader;
+ private Matrix mMatrix = new Matrix();
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ Bitmap rawBitmap = getBitmap(getDrawable());
+ if (rawBitmap != null) {
+ int viewWidth = getWidth();
+ int viewHeight = getHeight();
+ int viewMinSize = Math.min(viewWidth, viewHeight);
+ float dstWidth = viewMinSize;
+ float dstHeight = viewMinSize;
+ if (mShader == null || !rawBitmap.equals(mRawBitmap)) {
+ mRawBitmap = rawBitmap;
+ mShader = new BitmapShader(mRawBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ }
+ if (mShader != null) {
+ mMatrix.setScale(dstWidth / rawBitmap.getWidth(), dstHeight / rawBitmap.getHeight());
+ mShader.setLocalMatrix(mMatrix);
+ }
+ mPaintBitmap.setShader(mShader);
+ float radius = viewMinSize / 2.0f;
+ canvas.drawCircle(radius, radius, radius, mPaintBitmap);
+ } else {
+ super.onDraw(canvas);
+ }
+ }
+
+ private Bitmap getBitmap(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ } else if (drawable instanceof ColorDrawable) {
+ Rect rect = drawable.getBounds();
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ int color = ((ColorDrawable) drawable).getColor();
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
+ return bitmap;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/CommomDialog.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/CommomDialog.java
new file mode 100644
index 0000000..5d7a282
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/CommomDialog.java
@@ -0,0 +1,121 @@
+package com.qiniu.droid.niuplayer.widget;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.qiniu.droid.niuplayer.R;
+
+public class CommomDialog extends Dialog implements View.OnClickListener {
+ private TextView mTitleTxt;
+ private TextView mSubmitTxt;
+ private TextView mCancelTxt;
+ private EditText mEditText;
+
+ private Activity mActivity;
+ private OnCloseListener listener;
+ private String positiveName;
+ private String negativeName;
+ private String title;
+
+ public CommomDialog(Activity activity) {
+ this(activity, R.style.dialog, null);
+ }
+
+ public CommomDialog(Activity activity, int themeResId, String content) {
+ super(activity, themeResId);
+ this.mActivity = activity;
+ }
+
+ public CommomDialog(Activity activity, int themeResId, String content, OnCloseListener listener) {
+ super(activity, themeResId);
+ this.mActivity = activity;
+ this.listener = listener;
+ }
+
+ protected CommomDialog(Activity activity, boolean cancelable, OnCancelListener cancelListener) {
+ super(activity, cancelable, cancelListener);
+ this.mActivity = activity;
+ }
+
+ public String getEditString() {
+ return mEditText.getText().toString();
+ }
+
+ public CommomDialog setTitle(String title) {
+ this.title = title;
+ return this;
+ }
+
+ public CommomDialog setPositiveButton(String name) {
+ this.positiveName = name;
+ return this;
+ }
+
+ public CommomDialog setNegativeButton(String name) {
+ this.negativeName = name;
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.dialog_common);
+ setCanceledOnTouchOutside(false);
+ initView();
+ }
+
+ private void initView() {
+ mTitleTxt = (TextView) findViewById(R.id.title);
+ mSubmitTxt = (TextView) findViewById(R.id.submit);
+ mSubmitTxt.setOnClickListener(this);
+ mCancelTxt = (TextView) findViewById(R.id.cancel);
+ mEditText = findViewById(R.id.edit_text);
+ mCancelTxt.setOnClickListener(this);
+
+ if (!TextUtils.isEmpty(positiveName)) {
+ mSubmitTxt.setText(positiveName);
+ }
+
+ if (!TextUtils.isEmpty(negativeName)) {
+ mCancelTxt.setText(negativeName);
+ }
+
+ if (!TextUtils.isEmpty(title)) {
+ mTitleTxt.setText(title);
+ }
+
+ WindowManager windowManager = mActivity.getWindowManager();
+ Display display = windowManager.getDefaultDisplay();
+ WindowManager.LayoutParams lp = this.getWindow().getAttributes();
+ lp.width = (int) (display.getWidth() * 0.75);
+ this.getWindow().setAttributes(lp);
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.cancel:
+ if (listener != null) {
+ listener.onClick(this, false);
+ }
+ this.dismiss();
+ break;
+ case R.id.submit:
+ if (listener != null) {
+ listener.onClick(this, true);
+ }
+ break;
+ }
+ }
+
+ public interface OnCloseListener {
+ void onClick(Dialog dialog, boolean confirm);
+ }
+}
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/GestureControllerListener.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/GestureControllerListener.java
new file mode 100644
index 0000000..f090bb8
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/GestureControllerListener.java
@@ -0,0 +1,97 @@
+package com.qiniu.droid.niuplayer.widget;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.media.AudioManager;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+public class GestureControllerListener implements GestureDetector.OnGestureListener {
+ private float mCurVolume;
+ private Activity mActivity;
+
+ public GestureControllerListener(Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public boolean onDown(MotionEvent motionEvent) {
+ return true;
+ }
+
+ @Override
+ public void onShowPress(MotionEvent motionEvent) {
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent motionEvent) {
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ float touchX = e1.getX();
+ WindowManager wm = (WindowManager) mActivity
+ .getSystemService(Context.WINDOW_SERVICE);
+ int width = wm.getDefaultDisplay().getWidth();
+
+ final double FLING_MIN_DISTANCE = 0.5;
+ final double FLING_MIN_VELOCITY = 0.5;
+ if (e1.getY() - e2.getY() > FLING_MIN_DISTANCE
+ && Math.abs(distanceY) > FLING_MIN_VELOCITY) {
+ if (touchX > width / 2) {
+ setVolume(0.1f);
+ } else {
+ setBrightness(10);
+ }
+ }
+ if (e1.getY() - e2.getY() < FLING_MIN_DISTANCE
+ && Math.abs(distanceY) > FLING_MIN_VELOCITY) {
+ if (touchX > width / 2) {
+ setVolume(-0.1f);
+ } else {
+ setBrightness(-10);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onLongPress(MotionEvent motionEvent) {
+ }
+
+ @Override
+ public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
+ return false;
+ }
+
+ public void setVolume(float volume) {
+ AudioManager audioManager = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
+ int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); // 获取系统最大音量
+
+ if (mCurVolume == 0) {
+ mCurVolume = (float) (audioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+ }
+ mCurVolume += volume;
+ if (mCurVolume > maxVolume) {
+ mCurVolume = maxVolume;
+ } else if (mCurVolume < 0) {
+ mCurVolume = 0;
+ }
+ audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) mCurVolume, 0);
+ }
+
+ public void setBrightness(float brightness) {
+ WindowManager.LayoutParams lp = mActivity.getWindow().getAttributes();
+ lp.screenBrightness = lp.screenBrightness + brightness / 255.0f;
+ if (lp.screenBrightness > 1) {
+ lp.screenBrightness = 1;
+ } else if (lp.screenBrightness < 0.01) {
+ lp.screenBrightness = (float) 0.01;
+ }
+ mActivity.getWindow().setAttributes(lp);
+ }
+}
+
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/MediaController.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/MediaController.java
new file mode 100644
index 0000000..24fec43
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/MediaController.java
@@ -0,0 +1,603 @@
+package com.qiniu.droid.niuplayer.widget;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.media.AudioManager;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.PopupWindow;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.pili.pldroid.player.IMediaController;
+import com.qiniu.droid.niuplayer.R;
+
+import java.util.Locale;
+
+/**
+ * You can write a custom MediaController instead of this class
+ * A MediaController widget must implement all the interface defined by com.pili.pldroid.player.IMediaController
+ */
+public class MediaController extends FrameLayout implements IMediaController {
+
+ private static final String TAG = "PLMediaController";
+ private IMediaController.MediaPlayerControl mPlayer;
+ private Context mContext;
+ private PopupWindow mWindow;
+ private int mAnimStyle;
+ private View mAnchor;
+ private View mRoot;
+ private ProgressBar mProgress;
+ private TextView mEndTime, mCurrentTime;
+ private long mDuration;
+ private boolean mShowing;
+ private boolean mDragging;
+ private boolean mInstantSeeking = true;
+ private static int sDefaultTimeout = 3000;
+ private static final int SEEK_TO_POST_DELAY_MILLIS = 200;
+
+ private static final int FADE_OUT = 1;
+ private static final int SHOW_PROGRESS = 2;
+ private boolean mFromXml = false;
+ private ImageButton mPauseButton;
+ private ImageButton mFfwdButton;
+ private ImageButton mRewButton;
+ private ImageButton mNextButton;
+ private ImageButton mPrevButton;
+
+ private boolean mUseFastForward;
+
+ private static final int MEDIA_CONTROLLER_ID = Resources.getSystem().getIdentifier("media_controller", "layout", "android");
+ private static final int PRV_BUTTON_ID = Resources.getSystem().getIdentifier("prev","id", "android");
+ private static final int FFWD_BUTTON_ID = Resources.getSystem().getIdentifier("ffwd","id", "android");
+ private static final int NEXT_BUTTON_ID = Resources.getSystem().getIdentifier("next","id", "android");
+ private static final int REW_BUTTON_ID = Resources.getSystem().getIdentifier("rew","id", "android");
+
+ private static int PAUSE_BUTTON_ID = Resources.getSystem().getIdentifier("pause","id", "android");
+ private static int MEDIACONTROLLER_PROGRESS_ID = Resources.getSystem().getIdentifier("mediacontroller_progress","id", "android");
+ private static int END_TIME_ID = Resources.getSystem().getIdentifier("time","id", "android");
+ private static int CURRENT_TIME_ID = Resources.getSystem().getIdentifier("time_current","id", "android");
+ private static int IC_MEDIA_PAUSE_ID = Resources.getSystem().getIdentifier("ic_media_pause","drawable", "android");
+ private static int IC_MEDIA_PLAY_ID = Resources.getSystem().getIdentifier("ic_media_play","drawable", "android");
+
+ private AudioManager mAM;
+ private Runnable mLastSeekBarRunnable;
+ private boolean mDisableProgress = false;
+ private OnClickSpeedAdjustListener mOnClickSpeedAdjustListener;
+
+ public interface OnClickSpeedAdjustListener {
+ void onClickNormal();
+ void onClickFaster();
+ void onClickSlower();
+ }
+
+ public MediaController(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mRoot = this;
+ mFromXml = true;
+ initController(context);
+ }
+
+ public MediaController(Context context) {
+ super(context);
+ if (!mFromXml && initController(context))
+ initFloatingWindow();
+ }
+
+ public MediaController(Context context, boolean useFastForward, boolean disableProgressBar) {
+ this(context);
+ mUseFastForward = useFastForward;
+ mDisableProgress = disableProgressBar;
+ }
+
+ public MediaController(Context context, boolean useFastForward) {
+ this(context);
+ mUseFastForward = useFastForward;
+ }
+
+ public void refreshProgress() {
+ mProgress.setProgress(1000);
+ mCurrentTime.setText(generateTime(mDuration));
+ }
+
+ public void setOnClickSpeedAdjustListener(OnClickSpeedAdjustListener listener) {
+ mOnClickSpeedAdjustListener = listener;
+ }
+
+ private boolean initController(Context context) {
+ mUseFastForward = true;
+ mContext = context.getApplicationContext();
+ mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ return true;
+ }
+
+ @Override
+ public void onFinishInflate() {
+ if (mRoot != null)
+ initControllerView(mRoot);
+ super.onFinishInflate();
+ }
+
+ private void initFloatingWindow() {
+ mWindow = new PopupWindow(mContext);
+ mWindow.setFocusable(false);
+ mWindow.setBackgroundDrawable(null);
+ mWindow.setOutsideTouchable(true);
+ mAnimStyle = android.R.style.Animation;
+ }
+
+ /**
+ * Create the view that holds the widgets that control playback. Derived
+ * classes can override this to create their own.
+ *
+ * @return The controller view.
+ */
+ protected View makeControllerView() {
+ return ((LayoutInflater) mContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(MEDIA_CONTROLLER_ID, this);
+ }
+
+ private void initControllerView(View v) {
+ if (mFromXml){
+ PAUSE_BUTTON_ID = R.id.controller_stop_play;
+ MEDIACONTROLLER_PROGRESS_ID = R.id.controller_progress_bar;
+ END_TIME_ID = R.id.controller_end_time;
+ CURRENT_TIME_ID = R.id.controller_current_time;
+ IC_MEDIA_PAUSE_ID = R.drawable.player_stop;
+ IC_MEDIA_PLAY_ID = R.drawable.play_player;
+ }
+
+ // By default these are hidden.
+ mPrevButton = (ImageButton) v.findViewById(PRV_BUTTON_ID);
+ if (mPrevButton != null) {
+ mPrevButton.setVisibility(View.GONE);
+ }
+ mNextButton = (ImageButton) v.findViewById(NEXT_BUTTON_ID);
+ if (mNextButton != null) {
+ mNextButton.setVisibility(View.GONE);
+ }
+
+ mFfwdButton = (ImageButton) v.findViewById(FFWD_BUTTON_ID);
+ if (mFfwdButton != null) {
+ mFfwdButton.setOnClickListener(mFfwdListener);
+ if (!mFromXml) {
+ mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ mRewButton = (ImageButton) v.findViewById(REW_BUTTON_ID);
+ if (mRewButton != null) {
+ mRewButton.setOnClickListener(mRewListener);
+ if (!mFromXml) {
+ mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
+ }
+ }
+ mPauseButton = (ImageButton) v.findViewById(PAUSE_BUTTON_ID);
+ if (mPauseButton != null) {
+ mPauseButton.requestFocus();
+ mPauseButton.setOnClickListener(mPauseListener);
+ }
+
+ mProgress = (ProgressBar) v.findViewById(MEDIACONTROLLER_PROGRESS_ID);
+ if (mProgress != null) {
+ if (mProgress instanceof SeekBar) {
+ SeekBar seeker = (SeekBar) mProgress;
+ seeker.setOnSeekBarChangeListener(mSeekListener);
+ seeker.setThumbOffset(1);
+ }
+ mProgress.setMax(1000);
+ mProgress.setEnabled(!mDisableProgress);
+ }
+
+ mEndTime = (TextView) v.findViewById(END_TIME_ID);
+ mCurrentTime = (TextView) v.findViewById(CURRENT_TIME_ID);
+ }
+
+ /**
+ * Control the action when the seekbar dragged by user
+ *
+ * @param seekWhenDragging
+ * True the media will seek periodically
+ */
+ public void setInstantSeeking(boolean seekWhenDragging) {
+ mInstantSeeking = seekWhenDragging;
+ }
+
+ private void disableUnsupportedButtons() {
+ try {
+ if (mPauseButton != null && !mPlayer.canPause())
+ mPauseButton.setEnabled(false);
+ } catch (IncompatibleClassChangeError ex) {
+ }
+ }
+
+ /**
+ *
+ * Change the animation style resource for this controller.
+ *
+ *
+ *
+ * If the controller is showing, calling this method will take effect only
+ * the next time the controller is shown.
+ *
+ *
+ * @param animationStyle
+ * animation style to use when the controller appears and disappears.
+ * Set to -1 for the default animation, 0 for no animation,
+ * or a resource identifier for an explicit animation.
+ *
+ */
+ public void setAnimationStyle(int animationStyle) {
+ mAnimStyle = animationStyle;
+ }
+
+
+ public interface OnShownListener {
+ public void onShown();
+ }
+
+ private OnShownListener mShownListener;
+
+ public void setOnShownListener(OnShownListener l) {
+ mShownListener = l;
+ }
+
+ public interface OnHiddenListener {
+ public void onHidden();
+ }
+
+ private OnHiddenListener mHiddenListener;
+
+ public void setOnHiddenListener(OnHiddenListener l) {
+ mHiddenListener = l;
+ }
+
+ @SuppressLint("HandlerLeak")
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ long pos;
+ switch (msg.what) {
+ case FADE_OUT:
+ hide();
+ break;
+ case SHOW_PROGRESS:
+ if (!mPlayer.isPlaying()) {
+ return;
+ }
+ pos = setProgress();
+ if (pos == -1) {
+ return;
+ }
+ if (!mDragging && mShowing) {
+ msg = obtainMessage(SHOW_PROGRESS);
+ sendMessageDelayed(msg, 1000 - (pos % 1000));
+ updatePausePlay();
+ }
+ break;
+ }
+ }
+ };
+
+ private long setProgress() {
+ if (mPlayer == null || mDragging) {
+ return 0;
+ }
+
+ long position = mPlayer.getCurrentPosition();
+ long duration = mPlayer.getDuration();
+ if (mProgress != null) {
+ if (duration > 0) {
+ long pos = 1000L * position / duration;
+ mProgress.setProgress((int) pos);
+ }
+ int percent = mPlayer.getBufferPercentage();
+ mProgress.setSecondaryProgress(percent * 10);
+ }
+
+ mDuration = duration;
+
+ if (mEndTime != null)
+ mEndTime.setText(generateTime(mDuration));
+ if (mCurrentTime != null)
+ mCurrentTime.setText(generateTime(position));
+
+ return position;
+ }
+
+ private static String generateTime(long position) {
+ int totalSeconds = (int) (position / 1000);
+
+ int seconds = totalSeconds % 60;
+ int minutes = (totalSeconds / 60) % 60;
+ int hours = totalSeconds / 3600;
+
+ if (hours > 0) {
+ return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,
+ seconds).toString();
+ } else {
+ return String.format(Locale.US, "%02d:%02d", minutes, seconds)
+ .toString();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ show(sDefaultTimeout);
+ return true;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev) {
+ show(sDefaultTimeout);
+ return false;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ int keyCode = event.getKeyCode();
+ if (event.getRepeatCount() == 0
+ && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
+ || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
+ doPauseResume();
+ show(sDefaultTimeout);
+ if (mPauseButton != null)
+ mPauseButton.requestFocus();
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
+ if (mPlayer.isPlaying()) {
+ mPlayer.pause();
+ updatePausePlay();
+ }
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_BACK
+ || keyCode == KeyEvent.KEYCODE_MENU) {
+ hide();
+ return true;
+ } else {
+ show(sDefaultTimeout);
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ private OnClickListener mPauseListener = new OnClickListener() {
+ public void onClick(View v) {
+ if (mOnClickSpeedAdjustListener != null) {
+ mOnClickSpeedAdjustListener.onClickNormal();
+ }
+ doPauseResume();
+ show(sDefaultTimeout);
+ }
+ };
+
+ private void updatePausePlay() {
+ if (mRoot == null || mPauseButton == null)
+ return;
+
+ if (mPlayer.isPlaying())
+ mPauseButton.setImageResource(IC_MEDIA_PAUSE_ID);
+ else
+ mPauseButton.setImageResource(IC_MEDIA_PLAY_ID);
+ }
+
+ private void doPauseResume() {
+ if (mPlayer.isPlaying())
+ mPlayer.pause();
+ else
+ mPlayer.start();
+ updatePausePlay();
+ }
+
+ private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
+
+ public void onStartTrackingTouch(SeekBar bar) {
+ mDragging = true;
+ show(3600000);
+ mHandler.removeMessages(SHOW_PROGRESS);
+ if (mInstantSeeking)
+ mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
+ }
+
+ public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
+ if (!fromuser) {
+ return;
+ }
+
+
+ final long newposition = (long) (mDuration * progress) / 1000;
+ String time = generateTime(newposition);
+ if (mInstantSeeking) {
+ mHandler.removeCallbacks(mLastSeekBarRunnable);
+ mLastSeekBarRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mPlayer.seekTo(newposition);
+ }
+ };
+ mHandler.postDelayed(mLastSeekBarRunnable, SEEK_TO_POST_DELAY_MILLIS);
+ }
+ if (mCurrentTime != null)
+ mCurrentTime.setText(time);
+ }
+
+ public void onStopTrackingTouch(SeekBar bar) {
+ if (!mInstantSeeking)
+ mPlayer.seekTo(mDuration * bar.getProgress() / 1000);
+
+ show(sDefaultTimeout);
+ mHandler.removeMessages(SHOW_PROGRESS);
+ mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
+ mDragging = false;
+ mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
+ }
+ };
+
+ private OnClickListener mRewListener = new OnClickListener() {
+ public void onClick(View v) {
+ if (mOnClickSpeedAdjustListener != null) {
+ mOnClickSpeedAdjustListener.onClickSlower();
+ }
+ show(sDefaultTimeout);
+ }
+ };
+
+ private OnClickListener mFfwdListener = new OnClickListener() {
+ public void onClick(View v) {
+ if (mOnClickSpeedAdjustListener != null) {
+ mOnClickSpeedAdjustListener.onClickFaster();
+ }
+ show(sDefaultTimeout);
+ }
+ };
+
+ /**
+ * Set the view that acts as the anchor for the control view.
+ *
+ * - This can for example be a VideoView, or your Activity's main view.
+ * - AudioPlayer has no anchor view, so the view parameter will be null.
+ *
+ * @param view
+ * The view to which to anchor the controller when it is visible.
+ */
+ @Override
+ public void setAnchorView(View view) {
+ mAnchor = view;
+ if (mAnchor == null) {
+ sDefaultTimeout = 0; // show forever
+ }
+ if (!mFromXml) {
+ removeAllViews();
+ mRoot = makeControllerView();
+ mWindow.setContentView(mRoot);
+ mWindow.setWidth(LayoutParams.MATCH_PARENT);
+ mWindow.setHeight(LayoutParams.WRAP_CONTENT);
+ }
+ initControllerView(mRoot);
+ }
+
+ @Override
+ public void setMediaPlayer(MediaPlayerControl player) {
+ mPlayer = player;
+ updatePausePlay();
+ }
+
+ @Override
+ public void show() {
+ show(sDefaultTimeout);
+ }
+
+ /**
+ * Show the controller on screen. It will go away automatically after
+ * 'timeout' milliseconds of inactivity.
+ *
+ * @param timeout
+ * The timeout in milliseconds. Use 0 to show the controller until hide() is called.
+ */
+ @Override
+ public void show(int timeout) {
+ if (!mShowing) {
+ if (mAnchor != null && mAnchor.getWindowToken() != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ }
+ }
+ if (mPauseButton != null)
+ mPauseButton.requestFocus();
+ disableUnsupportedButtons();
+
+ if (mFromXml) {
+ setVisibility(View.VISIBLE);
+ } else {
+ int[] location = new int[2];
+
+ if (mAnchor != null) {
+ mAnchor.getLocationOnScreen(location);
+ Rect anchorRect = new Rect(location[0], location[1],
+ location[0] + mAnchor.getWidth(), location[1]
+ + mAnchor.getHeight());
+
+ mWindow.setAnimationStyle(mAnimStyle);
+ mRoot.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ mWindow.showAsDropDown(mAnchor, 0, -mRoot.getMeasuredHeight());
+ } else {
+ Rect anchorRect = new Rect(location[0], location[1],
+ location[0] + mRoot.getWidth(), location[1]
+ + mRoot.getHeight());
+
+ mWindow.setAnimationStyle(mAnimStyle);
+ mWindow.showAtLocation(mRoot, Gravity.BOTTOM,
+ anchorRect.left, 0);
+ }
+ }
+ mShowing = true;
+ if (mShownListener != null)
+ mShownListener.onShown();
+ }
+ updatePausePlay();
+ mHandler.sendEmptyMessage(SHOW_PROGRESS);
+
+ if (timeout != 0) {
+ mHandler.removeMessages(FADE_OUT);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT),
+ timeout);
+ }
+ }
+
+ @Override
+ public boolean isShowing() {
+ return mShowing;
+ }
+
+ @Override
+ public void hide() {
+ if (mShowing) {
+ if (mAnchor != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ //mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+ }
+ }
+ try {
+ mHandler.removeMessages(SHOW_PROGRESS);
+ if (mFromXml)
+ setVisibility(View.GONE);
+ else
+ mWindow.dismiss();
+ } catch (IllegalArgumentException ex) {
+ Log.d(TAG, "MediaController already removed");
+ }
+ mShowing = false;
+ if (mHiddenListener != null)
+ mHiddenListener.onHidden();
+ }
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (mPauseButton != null) {
+ mPauseButton.setEnabled(enabled);
+ }
+ if (mFfwdButton != null) {
+ mFfwdButton.setEnabled(enabled);
+ }
+ if (mRewButton != null) {
+ mRewButton.setEnabled(enabled);
+ }
+ if (mProgress != null && !mDisableProgress)
+ mProgress.setEnabled(enabled);
+ disableUnsupportedButtons();
+ super.setEnabled(enabled);
+ }
+}
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/PlayConfigView.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/PlayConfigView.java
new file mode 100644
index 0000000..bb46140
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/PlayConfigView.java
@@ -0,0 +1,198 @@
+package com.qiniu.droid.niuplayer.widget;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.pili.pldroid.player.AVOptions;
+import com.pili.pldroid.player.widget.PLVideoTextureView;
+import com.qiniu.droid.niuplayer.R;
+import com.qiniu.droid.niuplayer.utils.Config;
+
+import static com.qiniu.droid.niuplayer.utils.Utils.createAVOptions;
+
+public class PlayConfigView extends LinearLayout implements View.OnClickListener {
+ public static final String BACKSTAGE_PLAY_TAG = "backstage_play";
+
+ private PLVideoTextureView mVideoView;
+ private boolean mIsMirror;
+ private boolean mIsCache;
+ private boolean mIsBackstagePlay;
+ private int mRotation;
+ private TextView mCurSpeedText;
+ private TextView mCurDisplayText;
+ private TextView mCurSpeedTipText;
+ private TextView mSaveTip;
+
+ public PlayConfigView(Context context) {
+ super(context);
+ }
+
+ public PlayConfigView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ View view = LayoutInflater.from(context).inflate(R.layout.view_play_config, this);
+ ImageView imageView = view.findViewById(R.id.close_image);
+ imageView.setOnClickListener(this);
+
+ ViewGroup viewGroup = view.findViewById(R.id.mirror_group);
+ viewGroup.setOnClickListener(this);
+
+ viewGroup = view.findViewById(R.id.rotate_group);
+ viewGroup.setOnClickListener(this);
+
+ viewGroup = view.findViewById(R.id.save_group);
+ viewGroup.setOnClickListener(this);
+
+ viewGroup = view.findViewById(R.id.backstage_group);
+ viewGroup.setOnClickListener(this);
+
+ mCurSpeedTipText = view.findViewById(R.id.speed_current_text);
+
+ TextView textView = view.findViewById(R.id.render_default);
+ textView.setOnClickListener(this);
+
+ mCurDisplayText = view.findViewById(R.id.render_full);
+ mCurDisplayText.setOnClickListener(this);
+
+ textView = view.findViewById(R.id.render_16_9);
+ textView.setOnClickListener(this);
+
+ textView = view.findViewById(R.id.render_4_3);
+ textView.setOnClickListener(this);
+
+ textView = view.findViewById(R.id.speed_05);
+ textView.setOnClickListener(this);
+
+ textView = view.findViewById(R.id.speed_075);
+ textView.setOnClickListener(this);
+
+ mCurSpeedText = view.findViewById(R.id.speed_1);
+ mCurSpeedText.setOnClickListener(this);
+
+ textView = view.findViewById(R.id.speed_125);
+ textView.setOnClickListener(this);
+
+ textView = view.findViewById(R.id.speed_15);
+ textView.setOnClickListener(this);
+
+ mSaveTip = view.findViewById(R.id.save_tip);
+ }
+
+ public void setVideoView(PLVideoTextureView videoView) {
+ if (videoView.equals(mVideoView)) {
+ return;
+ }
+ mVideoView = videoView;
+ resetConfig();
+ }
+
+ private void resetConfig() {
+ mIsBackstagePlay = false;
+ mIsCache = false;
+ mIsMirror = false;
+ mRotation = 0;
+
+ setPlayDisplayMode(PLVideoTextureView.ASPECT_RATIO_PAVED_PARENT, R.id.render_full);
+ setPlaySpeed(1f, R.id.speed_1);
+ setVisibility(GONE);
+ mVideoView.setMirror(mIsMirror);
+ mVideoView.setRotation(mRotation);
+ }
+
+ @Override
+ public void onClick(View view) {
+ int viewId = view.getId();
+ switch (viewId) {
+ case R.id.mirror_group:
+ mIsMirror = !mIsMirror;
+ mVideoView.setMirror(mIsMirror);
+ break;
+ case R.id.rotate_group:
+ mRotation += 90;
+ mVideoView.setRotation(mRotation);
+ break;
+ case R.id.save_group:
+ switchCacheEnable();
+ break;
+ case R.id.backstage_group:
+ switchBackstagePlay();
+ break;
+ case R.id.render_default:
+ setPlayDisplayMode(PLVideoTextureView.ASPECT_RATIO_ORIGIN, viewId);
+ break;
+ case R.id.render_full:
+ setPlayDisplayMode(PLVideoTextureView.ASPECT_RATIO_PAVED_PARENT, viewId);
+ break;
+ case R.id.render_16_9:
+ setPlayDisplayMode(PLVideoTextureView.ASPECT_RATIO_16_9, viewId);
+ break;
+ case R.id.render_4_3:
+ setPlayDisplayMode(PLVideoTextureView.ASPECT_RATIO_4_3, viewId);
+ break;
+ case R.id.speed_05:
+ setPlaySpeed(0.5f, viewId);
+ break;
+ case R.id.speed_075:
+ setPlaySpeed(0.75f, viewId);
+ break;
+ case R.id.speed_1:
+ setPlaySpeed(1f, viewId);
+ break;
+ case R.id.speed_125:
+ setPlaySpeed(1.25f, viewId);
+ break;
+ case R.id.speed_15:
+ setPlaySpeed(1.5f, viewId);
+ break;
+ case R.id.close_image:
+ setVisibility(GONE);
+ break;
+ }
+ }
+
+ private void setPlayDisplayMode(int displayMode, int id) {
+ if (mCurDisplayText != null) {
+ mCurDisplayText.setTextColor(getResources().getColor(R.color.colorDefaultText));
+ }
+ mCurDisplayText = findViewById(id);
+ mCurDisplayText.setTextColor(getResources().getColor(R.color.colorTextChoice));
+ mVideoView.setDisplayAspectRatio(displayMode);
+ }
+
+ private void setPlaySpeed(float speed, int id) {
+ if (mCurSpeedText != null) {
+ mCurSpeedText.setTextColor(getResources().getColor(R.color.colorDefaultText));
+ }
+ mCurSpeedText = findViewById(id);
+ mCurSpeedText.setTextColor(getResources().getColor(R.color.colorTextChoice));
+ mVideoView.setPlaySpeed(speed);
+ mCurSpeedTipText.setText(mCurSpeedText.getText());
+ }
+
+ private void switchCacheEnable() {
+ mIsCache = !mIsCache;
+ AVOptions options = createAVOptions();
+ if (mIsCache) {
+ options.setString(AVOptions.KEY_CACHE_DIR, Config.DEFAULT_CACHE_DIR_PATH);
+ mSaveTip.setText("缓存已开");
+ } else {
+ mSaveTip.setText("本地缓存");
+ }
+ mVideoView.setAVOptions(options);
+ }
+
+ private void switchBackstagePlay() {
+ mIsBackstagePlay = !mIsBackstagePlay;
+ Object tag = mIsBackstagePlay ? BACKSTAGE_PLAY_TAG : null;
+ String tip = mIsBackstagePlay ? "后台播放已经开启!" : "后台播放已经关闭!";
+ mVideoView.setTag(tag);
+ Toast.makeText(this.getContext(), tip, Toast.LENGTH_LONG).show();
+ }
+}
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/ScrollEnableViewPager.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/ScrollEnableViewPager.java
new file mode 100644
index 0000000..433d159
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/ScrollEnableViewPager.java
@@ -0,0 +1,37 @@
+package com.qiniu.droid.niuplayer.widget;
+
+import android.content.Context;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+
+public class ScrollEnableViewPager extends ViewPager {
+ private boolean mScrollEnable = true;
+
+ public ScrollEnableViewPager(Context context) {
+ super(context);
+ }
+
+ public ScrollEnableViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setScrollEnable(boolean scrollEnable) {
+ mScrollEnable = scrollEnable;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return mScrollEnable && super.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mScrollEnable) {
+ return super.onInterceptTouchEvent(ev);
+ } else {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/UpgradeDialog.java b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/UpgradeDialog.java
new file mode 100755
index 0000000..88e5f22
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/java/com/qiniu/droid/niuplayer/widget/UpgradeDialog.java
@@ -0,0 +1,55 @@
+package com.qiniu.droid.niuplayer.widget;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.text.Html;
+import android.view.Display;
+import android.view.WindowManager;
+
+import com.qiniu.droid.niuplayer.R;
+import com.qiniu.droid.niuplayer.utils.DownloadService;
+
+public class UpgradeDialog {
+
+ public static void show(final Context context, String content, final String downloadUrl) {
+ if (isContextValid(context)) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.upgradeDialog);
+ builder.setTitle("发现新版本");
+ builder.setMessage(Html.fromHtml(content))
+ .setPositiveButton("立刻下载", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ goToDownload(context, downloadUrl);
+ }
+ })
+ .setNegativeButton("以后再说", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+
+
+ AlertDialog dialog = builder.create();
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.show();
+
+ WindowManager m = ((Activity) context).getWindowManager();
+ Display d = m.getDefaultDisplay();
+ android.view.WindowManager.LayoutParams p = dialog.getWindow().getAttributes();
+ p.width = (int) (d.getWidth() * 0.85);
+ dialog.getWindow().setAttributes(p);
+ }
+ }
+
+ private static boolean isContextValid(Context context) {
+ return context instanceof Activity && !((Activity) context).isFinishing();
+ }
+
+
+ private static void goToDownload(Context context, String downloadUrl) {
+ Intent intent = new Intent(context.getApplicationContext(), DownloadService.class);
+ intent.putExtra("url", downloadUrl);
+ context.startService(intent);
+ }
+}
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-hdpi/thumbnail.png b/NiuDroidPlayer/app/src/main/res/drawable-hdpi/thumbnail.png
new file mode 100644
index 0000000..31f093b
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-hdpi/thumbnail.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xhdpi/full_screen.png b/NiuDroidPlayer/app/src/main/res/drawable-xhdpi/full_screen.png
new file mode 100644
index 0000000..0dc540f
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xhdpi/full_screen.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/back.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/back.png
new file mode 100644
index 0000000..52959fc
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/back.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/background_play.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/background_play.png
new file mode 100644
index 0000000..63af0f4
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/background_play.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/btn_brightness.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/btn_brightness.png
new file mode 100755
index 0000000..4439e68
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/btn_brightness.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/close.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/close.png
new file mode 100644
index 0000000..5e9a5ac
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/close.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/defualt_bg.xml b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/defualt_bg.xml
new file mode 100644
index 0000000..d078e48
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/defualt_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/dialog_bg.xml b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/dialog_bg.xml
new file mode 100644
index 0000000..47f0c89
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/dialog_bg.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/dialog_edit_bg.xml b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/dialog_edit_bg.xml
new file mode 100644
index 0000000..278c0cd
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/dialog_edit_bg.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/face_icon.jpg b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/face_icon.jpg
new file mode 100644
index 0000000..f6d90dd
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/face_icon.jpg differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/failure.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/failure.png
new file mode 100644
index 0000000..093d7b1
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/failure.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/go.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/go.png
new file mode 100644
index 0000000..fca4df4
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/go.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/hks.jpg b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/hks.jpg
new file mode 100644
index 0000000..28a357f
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/hks.jpg differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/launch_image.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/launch_image.png
new file mode 100644
index 0000000..352e99d
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/launch_image.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/mirror_swtich.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/mirror_swtich.png
new file mode 100644
index 0000000..1b12c15
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/mirror_swtich.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/more.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/more.png
new file mode 100644
index 0000000..242809e
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/more.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/play.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/play.png
new file mode 100644
index 0000000..2132ab1
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/play.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/play_player.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/play_player.png
new file mode 100644
index 0000000..1848b86
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/play_player.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_back.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_back.png
new file mode 100644
index 0000000..5d0cf1c
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_back.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_close.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_close.png
new file mode 100644
index 0000000..9fa919f
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_close.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_stop.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_stop.png
new file mode 100644
index 0000000..f59ee10
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/player_stop.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/rotate.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/rotate.png
new file mode 100644
index 0000000..fc83e12
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/rotate.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/save.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/save.png
new file mode 100644
index 0000000..868e077
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/save.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/scan.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/scan.png
new file mode 100644
index 0000000..f0aa717
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/scan.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/screen_short.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/screen_short.png
new file mode 100644
index 0000000..b95c52a
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/screen_short.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/stop.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/stop.png
new file mode 100644
index 0000000..4729374
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/stop.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/tab_bottom_bg.xml b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/tab_bottom_bg.xml
new file mode 100644
index 0000000..3f4cf07
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/tab_bottom_bg.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/top_title_bg.xml b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/top_title_bg.xml
new file mode 100644
index 0000000..e89a31d
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/top_title_bg.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/url.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/url.png
new file mode 100644
index 0000000..d2df8dd
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/url.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/user.png b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/user.png
new file mode 100644
index 0000000..79e4beb
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/drawable-xxhdpi/user.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/layout/activity_main.xml b/NiuDroidPlayer/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..e1b7dfb
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/activity_pl_video_texture.xml b/NiuDroidPlayer/app/src/main/res/layout/activity_pl_video_texture.xml
new file mode 100644
index 0000000..75e8ba8
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/activity_pl_video_texture.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/activity_scan.xml b/NiuDroidPlayer/app/src/main/res/layout/activity_scan.xml
new file mode 100644
index 0000000..49864de
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/activity_scan.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/dialog_common.xml b/NiuDroidPlayer/app/src/main/res/layout/dialog_common.xml
new file mode 100644
index 0000000..fa920b5
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/dialog_common.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NiuDroidPlayer/app/src/main/res/layout/fragment_full_screen_video.xml b/NiuDroidPlayer/app/src/main/res/layout/fragment_full_screen_video.xml
new file mode 100644
index 0000000..1571860
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/fragment_full_screen_video.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/fragment_live_video_list.xml b/NiuDroidPlayer/app/src/main/res/layout/fragment_live_video_list.xml
new file mode 100644
index 0000000..5e46c36
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/fragment_live_video_list.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/fragment_movie_list.xml b/NiuDroidPlayer/app/src/main/res/layout/fragment_movie_list.xml
new file mode 100644
index 0000000..b44cb60
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/fragment_movie_list.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/fragment_short_video_list.xml b/NiuDroidPlayer/app/src/main/res/layout/fragment_short_video_list.xml
new file mode 100644
index 0000000..7ec6456
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/fragment_short_video_list.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/view_live_video.xml b/NiuDroidPlayer/app/src/main/res/layout/view_live_video.xml
new file mode 100644
index 0000000..87410e0
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/view_live_video.xml
@@ -0,0 +1,58 @@
+
+
+
+ ¬
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/view_media_controller.xml b/NiuDroidPlayer/app/src/main/res/layout/view_media_controller.xml
new file mode 100644
index 0000000..2931f0d
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/view_media_controller.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/view_movie_video.xml b/NiuDroidPlayer/app/src/main/res/layout/view_movie_video.xml
new file mode 100644
index 0000000..881511f
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/view_movie_video.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/view_play_config.xml b/NiuDroidPlayer/app/src/main/res/layout/view_play_config.xml
new file mode 100644
index 0000000..a6cd07c
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/view_play_config.xml
@@ -0,0 +1,276 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/layout/view_short_video.xml b/NiuDroidPlayer/app/src/main/res/layout/view_short_video.xml
new file mode 100644
index 0000000..991d202
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/layout/view_short_video.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/mipmap-hdpi/ic_launcher.png b/NiuDroidPlayer/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/mipmap-mdpi/ic_launcher.png b/NiuDroidPlayer/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/NiuDroidPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/NiuDroidPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/NiuDroidPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/mipmap-xxxhdpi/player_icon.png b/NiuDroidPlayer/app/src/main/res/mipmap-xxxhdpi/player_icon.png
new file mode 100644
index 0000000..00811c8
Binary files /dev/null and b/NiuDroidPlayer/app/src/main/res/mipmap-xxxhdpi/player_icon.png differ
diff --git a/NiuDroidPlayer/app/src/main/res/values-v21/styles.xml b/NiuDroidPlayer/app/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..dbbdd40
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/values-v21/styles.xml
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/values-w820dp/dimens.xml b/NiuDroidPlayer/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..b9bcbd3
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,7 @@
+
+
+ 64dp
+ 40dp
+
diff --git a/NiuDroidPlayer/app/src/main/res/values/colors.xml b/NiuDroidPlayer/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..b17ad40
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/values/colors.xml
@@ -0,0 +1,16 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
+ #9B9B9B
+ #cccccc
+ #52ffffff
+ #52a7fe
+ #dfdfdf
+ #dfdfdf
+ #60000000
+ #dff3f0
+ #f4f4f4
+
diff --git a/NiuDroidPlayer/app/src/main/res/values/dimens.xml b/NiuDroidPlayer/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..58fe034
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+ 40dp
+
diff --git a/NiuDroidPlayer/app/src/main/res/values/strings.xml b/NiuDroidPlayer/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..be6e8e4
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/values/strings.xml
@@ -0,0 +1,11 @@
+
+ 牛播放器
+
+ 二维码
+ 相册
+ 提示
+ 取消
+ 确定
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/values/styles.xml b/NiuDroidPlayer/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..89e27c4
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/values/styles.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NiuDroidPlayer/app/src/main/res/xml/update_apk_paths.xml b/NiuDroidPlayer/app/src/main/res/xml/update_apk_paths.xml
new file mode 100755
index 0000000..5722381
--- /dev/null
+++ b/NiuDroidPlayer/app/src/main/res/xml/update_apk_paths.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/NiuDroidPlayer/build.gradle b/NiuDroidPlayer/build.gradle
new file mode 100644
index 0000000..9c89fb3
--- /dev/null
+++ b/NiuDroidPlayer/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.1.3'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ google()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/NiuDroidPlayer/gradle.properties b/NiuDroidPlayer/gradle.properties
new file mode 100644
index 0000000..ded371d
--- /dev/null
+++ b/NiuDroidPlayer/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+android.injected.testOnly=false
diff --git a/NiuDroidPlayer/gradle/wrapper/gradle-wrapper.jar b/NiuDroidPlayer/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/NiuDroidPlayer/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/NiuDroidPlayer/gradle/wrapper/gradle-wrapper.properties b/NiuDroidPlayer/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..08b0aad
--- /dev/null
+++ b/NiuDroidPlayer/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon May 24 10:15:32 CST 2021
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
diff --git a/NiuDroidPlayer/gradlew b/NiuDroidPlayer/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/NiuDroidPlayer/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/NiuDroidPlayer/gradlew.bat b/NiuDroidPlayer/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/NiuDroidPlayer/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/NiuDroidPlayer/settings.gradle b/NiuDroidPlayer/settings.gradle
new file mode 100644
index 0000000..9d495b3
--- /dev/null
+++ b/NiuDroidPlayer/settings.gradle
@@ -0,0 +1 @@
+include ':app'
\ No newline at end of file
diff --git a/PLDroidPlayerDemo/app/build.gradle b/PLDroidPlayerDemo/app/build.gradle
index 24a9c93..4fce1fe 100644
--- a/PLDroidPlayerDemo/app/build.gradle
+++ b/PLDroidPlayerDemo/app/build.gradle
@@ -9,7 +9,7 @@ android {
minSdkVersion 14
targetSdkVersion 27
versionCode 13
- versionName "2.2.0"
+ versionName "2.2.2"
buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L"
}
buildTypes {
@@ -21,8 +21,9 @@ android {
sourceSets {
main {
- if (!useLibrary) {
- jniLibs.srcDirs = ['src/main/jniLibs']
+ jniLibs.srcDirs += ['../../releases/openssl']
+ if (useSo) {
+ jniLibs.srcDirs += ['../../releases/qplayer']
}
}
}
@@ -30,10 +31,14 @@ android {
dependencies {
- if (useLibrary) {
- implementation project(path: ':library')
+ if (!useJar) {
+ implementation project(path: ':PLDroidPlayer')
} else {
- implementation files('libs/pldroid-player-2.2.1.jar')
+ implementation files('../../releases/pldroid-player-2.2.2.jar')
+ }
+
+ if (!useSo) {
+ implementation project(path: ':mediaEngine')
}
implementation 'com.android.support:appcompat-v7:27.1.0'
diff --git a/PLDroidPlayerDemo/app/libs/pldroid-player-2.2.1.jar b/PLDroidPlayerDemo/app/libs/pldroid-player-2.2.1.jar
deleted file mode 100644
index 27b864a..0000000
Binary files a/PLDroidPlayerDemo/app/libs/pldroid-player-2.2.1.jar and /dev/null differ
diff --git a/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/MainActivity.java b/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/MainActivity.java
index d8f631b..cc23313 100644
--- a/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/MainActivity.java
+++ b/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/MainActivity.java
@@ -31,12 +31,14 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String DEFAULT_TEST_URL = "http://demo-videos.qnsdk.com/movies/qiniu.mp4";
+// private static final String DEFAULT_TEST_URL = "https://playback-cn.cloudlinks.cn/vas/playback/m3u8?ownerid=9223801851411955728&deviceid=429814557179925&startTime=1623910752&endTime=1623911216&sign=537a6c4b06b5e3e8cc3c091fbea01153726aa615";
private Spinner mActivitySpinner;
private EditText mEditText;
private RadioGroup mStreamingTypeRadioGroup;
private RadioGroup mDecodeTypeRadioGroup;
private CheckBox mVideoCacheCheckBox;
+ private CheckBox mVideoCacheFileNameEncodeCheckBox;
private CheckBox mLoopCheckBox;
private CheckBox mVideoDataCallback;
private CheckBox mAudioDataCallback;
@@ -75,6 +77,7 @@ protected void onCreate(Bundle savedInstanceState) {
mActivitySpinner.setSelection(2);
mVideoCacheCheckBox = findViewById(R.id.CacheCheckBox);
+ mVideoCacheFileNameEncodeCheckBox = findViewById(R.id.CacheFileNameEncodeCheckBox);
mLoopCheckBox = findViewById(R.id.LoopCheckBox);
mVideoDataCallback = findViewById(R.id.VideoCallback);
mAudioDataCallback = findViewById(R.id.AudioCallback);
@@ -207,6 +210,7 @@ public void jumpToPlayerActivity(String videoPath, boolean isList) {
intent.putExtra("liveStreaming", 0);
}
intent.putExtra("cache", mVideoCacheCheckBox.isChecked());
+ intent.putExtra("cache-filename-encode", mVideoCacheFileNameEncodeCheckBox.isChecked());
intent.putExtra("loop", mLoopCheckBox.isChecked());
intent.putExtra("video-data-callback", mVideoDataCallback.isChecked());
intent.putExtra("audio-data-callback", mAudioDataCallback.isChecked());
diff --git a/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/PLVideoViewActivity.java b/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/PLVideoViewActivity.java
index ce87484..04172db 100644
--- a/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/PLVideoViewActivity.java
+++ b/PLDroidPlayerDemo/app/src/main/java/com/pili/pldroid/playerdemo/PLVideoViewActivity.java
@@ -68,6 +68,9 @@ protected void onCreate(Bundle savedInstanceState) {
if (!mIsLiveStreaming && cache) {
options.setString(AVOptions.KEY_CACHE_DIR, Config.DEFAULT_CACHE_DIR);
}
+
+ boolean cache_filename_encode = getIntent().getBooleanExtra("cache-filename-encode", false);
+ options.setInteger(AVOptions.KEY_CACHE_FILE_NAME_ENCODE, cache_filename_encode ? 1: 0);
boolean vcallback = getIntent().getBooleanExtra("video-data-callback", false);
if (vcallback) {
options.setInteger(AVOptions.KEY_VIDEO_DATA_CALLBACK, 1);
@@ -260,7 +263,7 @@ public void onVideoSizeChanged(int width, int height) {
private PLOnVideoFrameListener mOnVideoFrameListener = new PLOnVideoFrameListener() {
@Override
public void onVideoFrameAvailable(byte[] data, int size, int width, int height, int format, long ts) {
- Log.i(TAG, "onVideoFrameAvailable: " + size + ", " + width + " x " + height + ", " + format + ", " + ts);
+ Log.i(TAG, "onVideoFrameAvailable: format=" + format + ", size=" + size + ", data-length="+ data.length + ", " + width + " x " + height + ", time=" + ts + " ,data=" + Arrays.toString(data));
if (format == PLOnVideoFrameListener.VIDEO_FORMAT_SEI && size > 0) {
// If the RTMP stream is from Qiniu
// Add &addtssei=true to the end of URL to enable SEI timestamp.
@@ -279,8 +282,11 @@ public void onVideoFrameAvailable(byte[] data, int size, int width, int height,
} while (data[index++] == (byte) 0xFF);
String uuid = bytesToHex(Arrays.copyOfRange(data, index, index + 16));
int length = payloadSize - 16;
- String content = new String(data, index + 16, length);
- Log.i(TAG, " SEI data size:" + data.length + " content: " + content + " length = " + length);
+ int start_index = index + 16;
+ if (start_index >= 0 && length > 0 && (start_index + length) <= data.length) {
+ String content = new String(data, index + 16, length);
+ Log.i(TAG, " SEI data size:" + data.length + " content: " + content + " length = " + length);
+ }
}
}
};
diff --git a/PLDroidPlayerDemo/app/src/main/jniLibs/arm64-v8a/libQPlayer.so b/PLDroidPlayerDemo/app/src/main/jniLibs/arm64-v8a/libQPlayer.so
deleted file mode 100755
index 5d3edb8..0000000
Binary files a/PLDroidPlayerDemo/app/src/main/jniLibs/arm64-v8a/libQPlayer.so and /dev/null differ
diff --git a/PLDroidPlayerDemo/app/src/main/jniLibs/x86/libQPlayer.so b/PLDroidPlayerDemo/app/src/main/jniLibs/x86/libQPlayer.so
deleted file mode 100755
index 0c7d2ca..0000000
Binary files a/PLDroidPlayerDemo/app/src/main/jniLibs/x86/libQPlayer.so and /dev/null differ
diff --git a/PLDroidPlayerDemo/app/src/main/res/layout/activity_main.xml b/PLDroidPlayerDemo/app/src/main/res/layout/activity_main.xml
index a1b62bd..e2594fd 100644
--- a/PLDroidPlayerDemo/app/src/main/res/layout/activity_main.xml
+++ b/PLDroidPlayerDemo/app/src/main/res/layout/activity_main.xml
@@ -141,7 +141,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cache" />
-
+
+
+
自动