Commit f838e2b9 authored by jianglx's avatar jianglx

im 上传未上传的文件

parent 21ac26e1
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 19
targetSdkVersion 26
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:appcompat-v7:26.0.0'
api 'de.greenrobot:eventbus:2.4.0'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/Nathen/WorkEnv/android-sdk-macosx/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fm.jiecao.jcvideoplayer_lib">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
\ No newline at end of file
package fm.jiecao.jcvideoplayer_lib;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* 这个ImageView用作于聊天发送图片
* 做了一个类似QQ发送图片的背景效果
* 此控件由Liuxuan大神编写
* 2017-7-19
*/
public class ChatImageView extends ImageView {
private Paint mBitPaint;
private int mTotalWidth;
private int mTotalHeight;
private RectF mSrcRect;
private Path path;
private int triangleY;
private int radius;
private boolean direction;
private boolean mFreezesAnimation;
public ChatImageView(Context context) {
this(context, null, 0);
}
public ChatImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ChatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, new int[]{R.attr.chat_direction});
direction = ta.getBoolean(0, false);
initPaint();
}
private void initPaint() {
mBitPaint = new Paint();
mBitPaint.setAntiAlias(true); //设置画笔为无锯齿
mBitPaint.setColor(Color.parseColor("#EBEBEB")); //设置画笔颜色
mBitPaint.setStrokeWidth(1f); //线宽
mBitPaint.setStyle(Paint.Style.FILL); //填充
triangleY = 30;
radius = 10;
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
invalidate();
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path, mBitPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mTotalWidth = w;
mTotalHeight = h;
if (direction) {
/* 圆角矩形 */
Path p = new Path();
RectF oval = new RectF(0, 0, mTotalWidth - 15, mTotalHeight);
p.addRoundRect(oval, radius, radius, Path.Direction.CCW);
/* 三角形 */
Path sanP = new Path();
sanP.moveTo(mTotalWidth - 15, triangleY);
sanP.lineTo(mTotalWidth, triangleY + 10);
sanP.lineTo(mTotalWidth - 15, triangleY + 20);
sanP.close();
/* 整个ImageView矩形 */
Path sizP = new Path();
RectF oo = new RectF(0, 0, mTotalWidth, mTotalHeight);
sizP.addRect(oo, Path.Direction.CCW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
p.op(sanP, Path.Op.XOR);
sizP.op(p, Path.Op.DIFFERENCE);
}
path = sizP;
} else {
/* 圆角矩形 */
Path p = new Path();
RectF oval = new RectF(15, 0, mTotalWidth, mTotalHeight);
p.addRoundRect(oval, radius, radius, Path.Direction.CCW);
/* 三角形 */
Path sanP = new Path();
sanP.moveTo(15, triangleY);
sanP.lineTo(0, triangleY + 10);
sanP.lineTo(15, triangleY + 20);
sanP.close();
/* 整个ImageView矩形 */
Path sizP = new Path();
RectF oo = new RectF(0, 0, mTotalWidth, mTotalHeight);
sizP.addRect(oo, Path.Direction.CCW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
p.op(sanP, Path.Op.XOR);
sizP.op(p, Path.Op.DIFFERENCE);
}
path = sizP;
}
}
/**
* @param y 三角形箭头与顶部的距离
*/
public void setTriangleY(int y) {
if (y < 30) {
triangleY = 30;
}
triangleY = y;
invalidate();
}
public void setRadius(int r) {
if (r > 100 || r < 5) {
r = 10;
}
radius = r;
invalidate();
}
public void setChatBackground(int color) {
mBitPaint.setColor(color);
invalidate();
}
/**
* @param b true = 右边
*/
public void setChatDirection(boolean b) {
direction = b;
invalidate();
}
}
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by dty on 2015/11/8.
* 单个下载线程
*/
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
public class FileDownloadThread extends Thread {
private static final int BUFFER_SIZE = 1024;
private URL url;
private File file;
private int startPosition;
private int endPosition;
private int curPosition;
//用于标识当前线程是否下载完成
private boolean finished = false;
private int downloadSize = 0;
public FileDownloadThread(URL url, File file, int startPosition, int endPosition) {
this.url = url;
this.file = file;
this.startPosition = startPosition;
this.curPosition = startPosition;
this.endPosition = endPosition;
}
@Override
public void run() {
BufferedInputStream bis = null;
RandomAccessFile fos = null;
byte[] buf = new byte[BUFFER_SIZE];
URLConnection con = null;
try {
con = url.openConnection();
con.setAllowUserInteraction(true);
//设置当前线程下载的起点,终点
con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
//使用java中的RandomAccessFile 对文件进行随机读写操作
fos = new RandomAccessFile(file, "rw");
//设置开始写文件的位置
fos.seek(startPosition);
bis = new BufferedInputStream(con.getInputStream());
//开始循环以流的形式读写文件
while (curPosition < endPosition) {
int len = bis.read(buf, 0, BUFFER_SIZE);
if (len == -1) {
break;
}
fos.write(buf, 0, len);
curPosition = curPosition + len;
if (curPosition > endPosition) {
downloadSize += len - (curPosition - endPosition) + 1;
} else {
downloadSize += len;
}
}
//下载完成设为true
this.finished = true;
bis.close();
fos.close();
} catch (IOException e) {
Log.d(getName() + " Error:", e.getMessage());
}
}
public boolean isFinished() {
return finished;
}
public int getDownloadSize() {
return downloadSize;
}
}
\ No newline at end of file
package fm.jiecao.jcvideoplayer_lib;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import java.lang.reflect.Method;
import java.util.Map;
/**
* <p>统一管理MediaPlayer的地方,只有一个mediaPlayer实例,那么不会有多个视频同时播放,也节省资源。</p>
* <p>Unified management MediaPlayer place, there is only one MediaPlayer instance, then there will be no more video broadcast at the same time, also save resources.</p>
* Created by Nathen
* On 2015/11/30 15:39
*/
public class JCMediaManager implements TextureView.SurfaceTextureListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnVideoSizeChangedListener {
public static final int HANDLER_PREPARE = 0;
public static final int HANDLER_RELEASE = 2;
public static String TAG = "JieCaoVideoPlayer";
public static JCResizeTextureView textureView;
public static SurfaceTexture savedSurfaceTexture;
public static String CURRENT_PLAYING_URL;
public static boolean CURRENT_PLING_LOOP;
public static Map<String, String> MAP_HEADER_DATA;
private static JCMediaManager JCMediaManager;
private static OnJcvdListener mJcvdListener;
public MediaPlayer mediaPlayer = new MediaPlayer();
public int currentVideoWidth = 0;
public int currentVideoHeight = 0;
HandlerThread mMediaHandlerThread;
MediaHandler mMediaHandler;
Handler mainThreadHandler;
public JCMediaManager() {
mMediaHandlerThread = new HandlerThread(TAG);
mMediaHandlerThread.start();
mMediaHandler = new MediaHandler((mMediaHandlerThread.getLooper()));
mainThreadHandler = new Handler();
}
public static JCMediaManager instance() {
if (JCMediaManager == null) {
JCMediaManager = new JCMediaManager();
}
return JCMediaManager;
}
public static void addOnJcvdListener(OnJcvdListener listener) {
mJcvdListener = listener;
}
public Point getVideoSize() {
if (currentVideoWidth != 0 && currentVideoHeight != 0) {
return new Point(currentVideoWidth, currentVideoHeight);
} else {
return null;
}
}
public void prepare() {
releaseMediaPlayer();
Message msg = new Message();
msg.what = HANDLER_PREPARE;
mMediaHandler.sendMessage(msg);
Log.e("xuan", "jcm prepare: ");
}
public void releaseMediaPlayer() {
Message msg = new Message();
msg.what = HANDLER_RELEASE;
mMediaHandler.sendMessage(msg);
Log.e("xuan", "jcm releaseMediaPlayer: ");
}
// Todo create 2018.11.29 by zq 全屏->小窗 主动调用onCompletion方法,结束播放,在全屏模式下循环播放
public void recoverMediaPlayer() {
mediaPlayer.release();
onCompletion(mediaPlayer);
Log.e("xuan", "jcm recoverMediaPlayer: ");
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
Log.i(TAG, "onSurfaceTextureAvailable [" + this.hashCode() + "] ");
if (savedSurfaceTexture == null) {
savedSurfaceTexture = surfaceTexture;
prepare();
} else {
textureView.setSurfaceTexture(savedSurfaceTexture);
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
// 如果SurfaceTexture还没有更新Image,则记录SizeChanged事件,否则忽略
Log.i(TAG, "onSurfaceTextureSizeChanged [" + this.hashCode() + "] ");
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return savedSurfaceTexture == null;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onPrepared();
}
if (mJcvdListener != null) {
mJcvdListener.onPrepared();
}
}
});
}
@Override
public void onCompletion(MediaPlayer mp) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onAutoCompletion();
}
if (mJcvdListener != null) {
mJcvdListener.onCompletion();
}
}
});
}
@Override
public void onBufferingUpdate(MediaPlayer mp, final int percent) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().setBufferProgress(percent);
}
}
});
}
@Override
public void onSeekComplete(MediaPlayer mp) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onSeekComplete();
}
}
});
}
@Override
public boolean onError(MediaPlayer mp, final int what, final int extra) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onError(what, extra);
}
if (mJcvdListener != null) {
mJcvdListener.onError();
}
}
});
return true;
}
@Override
public boolean onInfo(MediaPlayer mp, final int what, final int extra) {
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onInfo(what, extra);
}
}
});
return false;
}
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
currentVideoWidth = width;
currentVideoHeight = height;
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (JCVideoPlayerManager.getCurrentJcvd() != null) {
JCVideoPlayerManager.getCurrentJcvd().onVideoSizeChanged();
}
if (textureView != null) {
textureView.setVideoSize(getVideoSize());
}
}
});
}
public class MediaHandler extends Handler {
public MediaHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HANDLER_PREPARE:
try {
currentVideoWidth = 0;
currentVideoHeight = 0;
mediaPlayer.release();
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
Class<MediaPlayer> clazz = MediaPlayer.class;
Method method = clazz.getDeclaredMethod("setDataSource", String.class, Map.class);
method.invoke(mediaPlayer, CURRENT_PLAYING_URL, MAP_HEADER_DATA);
mediaPlayer.setLooping(false);
mediaPlayer.setOnPreparedListener(JCMediaManager.this);
mediaPlayer.setOnCompletionListener(JCMediaManager.this);
mediaPlayer.setOnBufferingUpdateListener(JCMediaManager.this);
mediaPlayer.setScreenOnWhilePlaying(true);
mediaPlayer.setOnSeekCompleteListener(JCMediaManager.this);
mediaPlayer.setOnErrorListener(JCMediaManager.this);
mediaPlayer.setOnInfoListener(JCMediaManager.this);
mediaPlayer.setOnVideoSizeChangedListener(JCMediaManager.this);
mediaPlayer.prepareAsync();
if (savedSurfaceTexture != null) {
mediaPlayer.setSurface(new Surface(savedSurfaceTexture));
}
} catch (Exception e) {
e.printStackTrace();
Log.e("xuan", "handleMessage: Exception--->" + e.getMessage());
}
break;
case HANDLER_RELEASE:
mediaPlayer.release();
break;
}
}
}
}
package fm.jiecao.jcvideoplayer_lib;
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;
/**
* <p>参照Android系统的VideoView的onMeasure方法
* <br>注意!relativelayout中无法全屏,要嵌套一个linearlayout</p>
* <p>Referring Android system Video View of onMeasure method
* <br>NOTE! Can not fullscreen relativelayout, to nest a linearlayout</p>
* Created by Nathen
* On 2016/06/02 00:01
*/
public class JCResizeTextureView extends TextureView {
protected static final String TAG = "JCResizeTextureView";
// x as width, y as height
protected Point mVideoSize;
public JCResizeTextureView(Context context) {
super(context);
init();
}
public JCResizeTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mVideoSize = new Point(0, 0);
}
public void setVideoSize(Point videoSize) {
if (videoSize != null && !mVideoSize.equals(videoSize)) {
this.mVideoSize = videoSize;
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 = mVideoSize.x;
int videoHeight = mVideoSize.y;
Log.i(TAG, "videoWidth = " + videoWidth + ", " + "videoHeight = " + videoHeight);
Log.i(TAG, "viewRotation = " + viewRotation);
// 如果判断成立,则说明显示的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
}
setMeasuredDimension(width, height);
}
}
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by Nathen
* On 2016/04/04 22:13
*/
public interface JCUserAction {
int ON_CLICK_START_ICON = 0;
int ON_CLICK_START_ERROR = 1;
int ON_CLICK_START_AUTO_COMPLETE = 2;
int ON_CLICK_PAUSE = 3;
int ON_CLICK_RESUME = 4;
int ON_SEEK_POSITION = 5;
int ON_AUTO_COMPLETE = 6;
int ON_ENTER_FULLSCREEN = 7;
int ON_QUIT_FULLSCREEN = 8;
int ON_ENTER_TINYSCREEN = 9;
int ON_QUIT_TINYSCREEN = 10;
int ON_TOUCH_SCREEN_SEEK_VOLUME = 11;
int ON_TOUCH_SCREEN_SEEK_POSITION = 12;
void onEvent(int type, String url, int screen, Object... objects);
}
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by Nathen
* On 2016/04/26 20:53
*/
public interface JCUserActionStandard extends JCUserAction {
int ON_CLICK_START_THUMB = 101;
int ON_CLICK_BLANK = 102;
}
package fm.jiecao.jcvideoplayer_lib;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import java.util.Formatter;
import java.util.Locale;
/**
* Created by Nathen
* On 2016/02/21 12:25
*/
public class JCUtils {
public static String stringForTime(int timeMs) {
if (timeMs <= 0 || timeMs >= 24 * 60 * 60 * 1000) {
return "00:00";
}
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = 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 a application 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 something
* @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;
}
/**
* Get AppCompatActivity from context
*
* @param context
* @return AppCompatActivity if it's not null
*/
public static AppCompatActivity getAppCompActivity(Context context) {
if (context == null)
return null;
if (context instanceof AppCompatActivity) {
return (AppCompatActivity) context;
}
return null;
}
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, String url, int progress) {
if (!JCVideoPlayer.SAVE_PROGRESS)
return;
SharedPreferences spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = spn.edit();
editor.putInt(url, progress);
editor.apply();
}
public static int getSavedProgress(Context context, String url) {
if (!JCVideoPlayer.SAVE_PROGRESS)
return 0;
SharedPreferences spn;
spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
return spn.getInt(url, 0);
}
/**
* if url == null, clear all progress
*
* @param context
* @param url if url!=null clear this url progress
*/
public static void clearSavedProgress(Context context, String url) {
if (TextUtils.isEmpty(url)) {
SharedPreferences spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
spn.edit().clear().apply();
} else {
SharedPreferences spn = context.getSharedPreferences("JCVD_PROGRESS",
Context.MODE_PRIVATE);
spn.edit().putInt(url, 0).apply();
}
}
}
package fm.jiecao.jcvideoplayer_lib;
/**
* Put JCVideoPlayer into layout
* From a JCVideoPlayer to another JCVideoPlayer
* Created by Nathen on 16/7/26.
*/
public class JCVideoPlayerManager {
public static JCVideoPlayer FIRST_FLOOR_JCVD;
public static JCVideoPlayer SECOND_FLOOR_JCVD;
public static void setFirstFloor(JCVideoPlayer jcVideoPlayer) {
FIRST_FLOOR_JCVD = jcVideoPlayer;
}
public static void setSecondFloor(JCVideoPlayer jcVideoPlayer) {
SECOND_FLOOR_JCVD = jcVideoPlayer;
}
public static JCVideoPlayer getFirstFloor() {
return FIRST_FLOOR_JCVD;
}
public static JCVideoPlayer getSecondFloor() {
return SECOND_FLOOR_JCVD;
}
public static JCVideoPlayer getCurrentJcvd() {
if (getSecondFloor() != null) {
return getSecondFloor();
}
return getFirstFloor();
}
public static void completeAll() {
if (SECOND_FLOOR_JCVD != null) {
SECOND_FLOOR_JCVD.onCompletion();
SECOND_FLOOR_JCVD = null;
}
if (FIRST_FLOOR_JCVD != null) {
FIRST_FLOOR_JCVD.onCompletion();
FIRST_FLOOR_JCVD = null;
}
}
}
package fm.jiecao.jcvideoplayer_lib;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;
/**
* Manage UI
* Created by Nathen
* On 2016/04/10 15:45
*/
public class JCVideoPlayerSimple extends JCVideoPlayer {
public JCVideoPlayerSimple(Context context) {
super(context);
}
public JCVideoPlayerSimple(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public int getLayoutId() {
return R.layout.jc_layout_base;
}
@Override
public void setUp(String url, int screen, Object... objects) {
super.setUp(url, screen, objects);
updateFullscreenButton();
fullscreenButton.setVisibility(View.GONE);
}
@Override
public void setUiWitStateAndScreen(int state) {
super.setUiWitStateAndScreen(state);
switch (currentState) {
case CURRENT_STATE_NORMAL:
startButton.setVisibility(View.VISIBLE);
break;
case CURRENT_STATE_PREPARING:
startButton.setVisibility(View.INVISIBLE);
break;
case CURRENT_STATE_PLAYING:
startButton.setVisibility(View.VISIBLE);
break;
case CURRENT_STATE_PAUSE:
break;
case CURRENT_STATE_ERROR:
break;
}
updateStartImage();
}
private void updateStartImage() {
if (currentState == CURRENT_STATE_PLAYING) {
startButton.setImageResource(R.drawable.jc_click_pause_selector);
} else if (currentState == CURRENT_STATE_ERROR) {
startButton.setImageResource(R.drawable.jc_click_error_selector);
} else {
startButton.setImageResource(R.drawable.jc_click_play_selector);
}
}
public void updateFullscreenButton() {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
fullscreenButton.setImageResource(R.drawable.jc_shrink);
} else {
fullscreenButton.setImageResource(R.drawable.jc_enlarge);
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.fullscreen && currentState == CURRENT_STATE_NORMAL) {
Toast.makeText(getContext(), "Play video first", Toast.LENGTH_SHORT).show();
return;
}
super.onClick(v);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
if (currentState == CURRENT_STATE_NORMAL) {
Toast.makeText(getContext(), "Play video first", Toast.LENGTH_SHORT).show();
return;
}
}
super.onProgressChanged(seekBar, progress, fromUser);
}
public void setUp(String url) {
super.setUp(url, JVCideoPlayerStandardSecond.SCREEN_LAYOUT_NORMAL, "");
}
}
package fm.jiecao.jcvideoplayer_lib;
import android.content.Context;
import android.media.AudioManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
/**
* Created by xuan on 2018-11-26 12:08:11.
* <p>
* 使用基于jcv视频播放器改造而成,用于短视频模块视频播放预览
*/
public class JCVideoViewbyXuan extends FrameLayout implements OnJcvdListener {
public int mCurrState;
public boolean loop = true;
public String mCurrUrl = "";
public boolean isForceFullScreenPlay;
protected AudioManager mAudioManager;
private OnJcvdListener mListener;
private AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
VideotillManager.instance().releaseVideo();
JCMediaManager.instance().releaseMediaPlayer();
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
try {
if (JCMediaManager.instance().mediaPlayer != null && JCMediaManager.instance().mediaPlayer.isPlaying()) {
JCMediaManager.instance().mediaPlayer.pause();
}
} catch (Exception e) {
}
}
}
};
public JCVideoViewbyXuan(Context context) {
super(context);
init(context);
}
public JCVideoViewbyXuan(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
public void setForceFullScreenPlay(boolean forceFullScreenPlay) {
isForceFullScreenPlay = forceFullScreenPlay;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isForceFullScreenPlay) {
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// setMeasuredDimension();
}
private void prepare() {
VideotillManager.instance().releaseVideo();
// 移除 管理器中的 textureView
JCMediaManager.savedSurfaceTexture = null;
if (JCMediaManager.textureView != null && JCMediaManager.textureView.getParent() != null) {
((ViewGroup) JCMediaManager.textureView.getParent()).removeView(JCMediaManager.textureView);
}
// 创建一个新的 textureView
JCMediaManager.textureView = new JCResizeTextureView(getContext());
JCMediaManager.textureView.setSurfaceTextureListener(JCMediaManager.instance());
// 放到容器中
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER);
this.addView(JCMediaManager.textureView, layoutParams);
// 当播放时才有焦点
JCUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
JCMediaManager.CURRENT_PLAYING_URL = this.mCurrUrl;
JCMediaManager.CURRENT_PLING_LOOP = loop;
JCMediaManager.MAP_HEADER_DATA = null;
JCMediaManager.addOnJcvdListener(this);
VideotillManager.instance().addVideoPlay(this);
mCurrState = JCVideoPlayer.CURRENT_STATE_PREPARING;
}
/**
* 播放 或 继续播放
*
* @param url
*/
public void play(String url) {
Log.e("xuan", "play: " + url + " state :" + mCurrState);
if (mCurrState == JCVideoPlayer.CURRENT_STATE_NORMAL) {
if (TextUtils.isEmpty(url)) {
return;
}
this.mCurrUrl = url;
prepare(); // !JCUtils.isWifiConnected(getContext()) 判断网络
} else if (mCurrState == JCVideoPlayer.CURRENT_STATE_PAUSE) {
JCMediaManager.instance().mediaPlayer.start(); // 开始
if (mListener != null) {
mListener.onPrepared();
}
mCurrState = JCVideoPlayer.CURRENT_STATE_PLAYING;
}
}
/**
* 暂停播放
*/
public void pause() {
Log.e("xuan", "pause: " + mCurrState);
if (mCurrState == JCVideoPlayer.CURRENT_STATE_PLAYING) {
if (JCMediaManager.instance().mediaPlayer.isPlaying()) {
JCMediaManager.instance().mediaPlayer.pause(); // 暂停
}
mCurrState = JCVideoPlayer.CURRENT_STATE_PAUSE;
if (mListener != null) {
mListener.onPause();
}
}
}
/**
* 停止播放
*/
public void stop() {
Log.e("xuan", "stop: " + mCurrState);
mCurrState = JCVideoPlayer.CURRENT_STATE_NORMAL;
JCMediaManager.instance().releaseMediaPlayer();
// 加上这句,避免循环播放video的时候,内存不断飙升。
Runtime.getRuntime().gc();
}
public void reset() {
Log.e("xuan", "reset: ");
JCMediaManager.instance().releaseMediaPlayer();
mCurrState = JCVideoPlayer.CURRENT_STATE_NORMAL;
// 清理缓存变量
this.removeView(JCMediaManager.textureView);
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
JCMediaManager.textureView = null;
JCMediaManager.savedSurfaceTexture = null;
// 加上这句,避免循环播放video的时候,内存不断飙升。
Runtime.getRuntime().gc();
if (mListener != null) {
mListener.onReset();
}
}
/**
* 修改系统音乐音量
*
* @param volume +10 or -10
*/
public void changeVolume(int volume) {
if (mCurrState == JCVideoPlayer.CURRENT_STATE_PLAYING && mAudioManager != null) {
// int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
int curr = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, curr + volume, 0);
}
}
/**
* 修改当前播放进度
*/
public void changeProgress(int pro) {
// 得到视频长度
int duration = getDuration();
// 将长度转换成时间
String totalTime = JCUtils.stringForTime(duration);
// 跳转到一个位置 毫秒
JCMediaManager.instance().mediaPlayer.seekTo(1000);
// 保存一个url的进度 or 清除进度
JCUtils.saveProgress(getContext(), mCurrUrl, 0);
JCUtils.clearSavedProgress(getContext(), mCurrUrl);
}
public void seekTo(int msec) {
// 跳转到一个位置 毫秒
JCMediaManager.instance().mediaPlayer.seekTo(msec);
}
/**
* 加载完成开始播放的回掉
*/
@Override
public void onPrepared() {
Log.e("xuan", "开始播放: " + mCurrUrl);
mCurrState = JCVideoPlayer.CURRENT_STATE_PLAYING;
if (mListener != null) {
mListener.onPrepared();
}
}
// 播放完成的回调
@Override
public void onCompletion() {
Log.e("xuan", "播放完成: ");
mCurrState = JCVideoPlayer.CURRENT_STATE_NORMAL;
if (mListener != null) {
mListener.onCompletion();
}
if (loop) {
mCurrState = JCVideoPlayer.CURRENT_STATE_PAUSE;
play(this.mCurrUrl);
}
}
@Override
public void onError() {
Log.e("xuan", "播放出错: " + mCurrUrl);
JCMediaManager.instance().releaseMediaPlayer();
mCurrState = JCVideoPlayer.CURRENT_STATE_NORMAL;
if (mListener != null) {
mListener.onError();
}
}
@Override
public void onPause() {
}
@Override
public void onReset() {
}
public int getCurrentProgress() {
int position = 0;
if (mCurrState == JCVideoPlayer.CURRENT_STATE_PLAYING || mCurrState == JCVideoPlayer.CURRENT_STATE_PAUSE) {
try {
position = JCMediaManager.instance().mediaPlayer.getCurrentPosition();
} catch (IllegalStateException e) {
e.printStackTrace();
return position;
}
}
return position;
}
public int getDuration() {
int duration = 0;
try {
duration = JCMediaManager.instance().mediaPlayer.getDuration();
} catch (IllegalStateException e) {
e.printStackTrace();
return duration;
}
return duration;
}
public void addOnJcvdListener(OnJcvdListener listener) {
this.mListener = listener;
}
public boolean isPlaying() {
return mCurrState == JCVideoPlayer.CURRENT_STATE_PLAYING;
}
}
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by Administrator on 2017/3/17 0017.
* 1. 视频播放控件 已准备,通知朋友圈页面停止播放录音,防止同时播放两种声音
* 2. 我的同事 其他页面调用api成功,通知同事页面刷新UI
* 3. 消息群发 收到回执后,通知群发页面,当群发页面收到所有人回执时,在隐藏等待符
* 4. 视频播放完成,通知单聊界面,判断是否为阅后即焚视频
*/
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
\ No newline at end of file
package fm.jiecao.jcvideoplayer_lib;
/**
* Created by xuan 改进jcv的通知回调方式
* On 2016/04/04 22:13
*/
public interface OnJcvdListener {
void onPrepared(); // 加载完成的回调
void onCompletion(); // 播放完成的回调
void onError(); // 播放出错
void onPause(); // 播放暂停
void onReset(); // 重置播放器
}
package fm.jiecao.jcvideoplayer_lib;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
public class SavaVideoDialog extends Dialog implements View.OnClickListener {
private TextView tv1;
private OnSavaVideoDialogClickListener mOnSavaVideoDialogClickListener;
public SavaVideoDialog(Context context, OnSavaVideoDialogClickListener mOnSavaVideoDialogClickListener) {
super(context, R.style.BottomDialog);
this.mOnSavaVideoDialogClickListener = mOnSavaVideoDialogClickListener;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_sava_video);
setCanceledOnTouchOutside(true);
initView();
}
private void initView() {
tv1 = (TextView) findViewById(R.id.tv1);
tv1.setOnClickListener(this);
Window o = getWindow();
WindowManager.LayoutParams lp = o.getAttributes();
// x/y坐标
// lp.x = 100;
// lp.y = 100;
lp.width = ScreenUtil.getScreenWidth(getContext());
o.setAttributes(lp);
this.getWindow().setGravity(Gravity.BOTTOM);
this.getWindow().setWindowAnimations(R.style.BottomDialog_Animation);
}
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.tv1) {
mOnSavaVideoDialogClickListener.tv1Click();
}
}
public interface OnSavaVideoDialogClickListener {
void tv1Click();
}
}
package fm.jiecao.jcvideoplayer_lib;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
/**
* Created by zq on 2017/9/19 0019.
*/
public class ScreenUtil {
private ScreenUtil() {
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 获取屏幕宽度
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 获取屏幕高度
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
/**
* 获取状态栏的高度
*/
public static int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen.xml");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
/**
* 获取当前屏幕截图,包含状态栏
*/
public static Bitmap snapShotWithStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bitmap = null;
bitmap = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return bitmap;
}
/**
* 获取当前屏幕截图,不包含状态栏
*/
public static Bitmap snapShotWithoutStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bitmap = null;
bitmap = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();
return bitmap;
}
}
package fm.jiecao.jcvideoplayer_lib;
import android.util.Log;
/**
* create by xuan 抖音视频管理器
*/
public class VideotillManager {
private static VideotillManager mVideotillManager;
private JCVideoViewbyXuan mVideo;
private VideotillManager() {
}
public static VideotillManager instance() {
if (mVideotillManager == null) {
mVideotillManager = new VideotillManager();
}
return mVideotillManager;
}
public void addVideoPlay(JCVideoViewbyXuan video) {
mVideo = video;
}
public void releaseVideo() {
if (mVideo != null) {
mVideo.reset();
mVideo = null;
}
}
public void play() {
if (mVideo != null) {
Log.e("xuan", "VideotillManager play: ");
mVideo.play("");
}
}
public void pause() {
Log.e("xuan", "VideotillManager pause: ");
if (mVideo != null && mVideo.isPlaying()) {
mVideo.pause();
}
}
}
package fm.jiecao.jcvideoplayer_lib;
import java.io.File;
import java.net.URL;
import java.net.URLConnection;
/**
* Created by dty on 2015/11/8.
*/
public class downloadTask extends Thread {
String urlStr, threadNo, fileName;
private int blockSize, downloadSizeMore;
private int threadNum = 5;
private int mDownloadedSize = 0;
private int fileSize = 0;
public downloadTask(String urlStr, int threadNum, String fileName) {
this.urlStr = urlStr;
this.threadNum = threadNum;
this.fileName = fileName;
}
/**
* @修改人:TanX
* @时间: 2016/4/19 17:22
* @参数:
* @说明: 这里会出现资源站没有该资源,而下载却一直在下载的情况,所以加个时间做超时
* 如果超过10秒下载的量依然没变,则超时
**/
@Override
public void run() {
FileDownloadThread[] fds = new FileDownloadThread[threadNum];
int overTime = 10000;//10秒超时
int downloadSize = 0;//初始下载为0
long downloadTime = System.currentTimeMillis();//起始下载时间
try {
// TanX.Log("开始下载,URL:" + urlStr);
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
//获取下载文件的总大小
fileSize = conn.getContentLength();
//计算每个线程要下载的数据量
blockSize = fileSize / threadNum;
// 解决整除后百分比计算误差
downloadSizeMore = (fileSize % threadNum);
File file = new File(fileName);
for (int i = 0; i < threadNum; i++) {
//启动线程,分别下载自己需要下载的部分
FileDownloadThread fdt = new FileDownloadThread(url, file,
i * blockSize, (i + 1) * blockSize - 1);
fdt.setName("Thread" + i);
fdt.start();
fds[i] = fdt;
}
boolean finished = false;
while (!finished) {
// TanX.Log("下载中");
if (System.currentTimeMillis() - downloadTime >= overTime) {
//到了超时的时限
if (mDownloadedSize <= downloadSize) {
// TanX.Log("总下载大小:" + mDownloadedSize);
//过了10秒,但是并没下载到东西,超时
throw new Exception();
}
//下载到了东西
downloadTime = System.currentTimeMillis();//重置时间
downloadSize = mDownloadedSize;//设置为当前的下载量
}
// 先把整除的余数搞定
mDownloadedSize = downloadSizeMore;
finished = true;
for (int i = 0; i < fds.length; i++) {
mDownloadedSize += fds[i].getDownloadSize();
if (!fds[i].isFinished()) {
finished = false;
}
}
}
// TanX.Log("下载完成");
} catch (Exception e) {
// TanX.Log("下载异常");
e.printStackTrace();
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<rotate
android:duration="5"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-2" />
</set>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment