@@ -54,14 +54,6 @@ public class V2XConst {
|
||||
public static final String V2X_ACC_OFF_TIME_STR = "v2x_acc_off_time_str";
|
||||
public static final String V2X_STRATEGY_PUSH = "v2x_strategy_push";
|
||||
|
||||
public static final int STATE_ERROR = -1;
|
||||
public static final int STATE_IDLE = 0;
|
||||
public static final int STATE_PREPARING = 1;
|
||||
public static final int STATE_PREPARED = 2;
|
||||
public static final int STATE_PLAYING = 3;
|
||||
public static final int STATE_PAUSED = 4;
|
||||
public static final int STATE_PLAYBACK_COMPLETED = 5;
|
||||
public static final int STATE_SEEKING = 6;
|
||||
|
||||
/**
|
||||
* V2X 埋点
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.mogo.module.v2x.R;
|
||||
import com.mogo.module.v2x.V2XServiceManager;
|
||||
import com.mogo.module.v2x.listener.V2XWindowStatusListener;
|
||||
import com.mogo.module.v2x.scenario.view.IV2XWindow;
|
||||
import com.mogo.module.v2x.view.TextureVideoView;
|
||||
import com.mogo.eagle.core.widget.TextureVideoView;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
package com.mogo.module.v2x.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.module.v2x.utils.ImageUtil;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加载图片帧动画
|
||||
*/
|
||||
public class AnimationView extends View implements Handler.Callback {
|
||||
|
||||
public static final int DEFAULT_ANIM_TIME = 20;
|
||||
public static final int PROCESS_DATA = 1;
|
||||
public static final int PROCESS_ANIM_FINISH = 1 << 1;
|
||||
public static final int PROCESS_DELAY = 1 << 2;
|
||||
|
||||
public AnimData mCurAnimData;
|
||||
public int mCurAnimPos;
|
||||
public boolean mIsRepeat;
|
||||
public int mAnimTime;
|
||||
|
||||
private Handler mHandler;
|
||||
private ProcessAnimThread mProcessThread;
|
||||
private Bitmap mCurShowBmp;
|
||||
|
||||
private List<AnimData> mAnimDataList = new ArrayList<>();
|
||||
|
||||
public AnimationView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AnimationView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AnimationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mHandler = new Handler(this);
|
||||
mProcessThread = new ProcessAnimThread(getContext(), mHandler);
|
||||
mAnimTime = DEFAULT_ANIM_TIME;
|
||||
}
|
||||
|
||||
public void setIsRepeat(boolean repeat) {
|
||||
mIsRepeat = repeat;
|
||||
}
|
||||
|
||||
private int mGravity;
|
||||
|
||||
public void setGravity(int gravity) {
|
||||
mGravity = gravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setData(List<AnimData> list) {
|
||||
if (list != null) {
|
||||
mAnimDataList.clear();
|
||||
mAnimDataList.addAll(list);
|
||||
}
|
||||
}
|
||||
|
||||
private Matrix mTempMatrix = new Matrix();
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mCurShowBmp != null && !mCurShowBmp.isRecycled()) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
float scaleX = 1f;
|
||||
float scaleY = 1f;
|
||||
switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
|
||||
case Gravity.LEFT:
|
||||
x = 0;
|
||||
break;
|
||||
case Gravity.RIGHT:
|
||||
x = this.getWidth() - mCurShowBmp.getWidth();
|
||||
break;
|
||||
case Gravity.CENTER_HORIZONTAL:
|
||||
x = (this.getWidth() - mCurShowBmp.getWidth()) / 2;
|
||||
break;
|
||||
case Gravity.FILL_HORIZONTAL: {
|
||||
int w = mCurShowBmp.getWidth();
|
||||
if (w > 0) {
|
||||
scaleX = (float) this.getWidth() / (float) w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
|
||||
case Gravity.TOP:
|
||||
y = 0;
|
||||
break;
|
||||
|
||||
case Gravity.BOTTOM:
|
||||
y = this.getHeight() - mCurShowBmp.getHeight();
|
||||
break;
|
||||
|
||||
case Gravity.CENTER_VERTICAL:
|
||||
y = (this.getHeight() - mCurShowBmp.getHeight()) / 2;
|
||||
break;
|
||||
|
||||
case Gravity.FILL_VERTICAL: {
|
||||
int h = mCurShowBmp.getHeight();
|
||||
if (h > 0) {
|
||||
scaleY = (float) this.getHeight() / (float) h;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (scaleX == 1 && scaleY != 1) {
|
||||
scaleX = scaleY;
|
||||
switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
|
||||
case Gravity.RIGHT:
|
||||
x = this.getWidth() - (int) (mCurShowBmp.getWidth() * scaleX);
|
||||
break;
|
||||
case Gravity.CENTER_HORIZONTAL:
|
||||
x = (this.getWidth() - (int) (mCurShowBmp.getWidth() * scaleX)) / 2;
|
||||
break;
|
||||
}
|
||||
} else if (scaleX != 1 && scaleY == 1) {
|
||||
scaleY = scaleX;
|
||||
switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
|
||||
case Gravity.BOTTOM:
|
||||
y = this.getHeight() - (int) (mCurShowBmp.getHeight() * scaleY);
|
||||
break;
|
||||
case Gravity.CENTER_VERTICAL:
|
||||
y = (this.getHeight() - (int) (mCurShowBmp.getHeight() * scaleY)) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mTempMatrix.reset();
|
||||
mTempMatrix.postScale(scaleX, scaleY);
|
||||
mTempMatrix.postTranslate(x, y);
|
||||
canvas.drawBitmap(mCurShowBmp, mTempMatrix, null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mHasStarted = false;
|
||||
|
||||
public void start() {
|
||||
mHasStarted = true;
|
||||
if (mWidth == 0 || mHeight == 0) {
|
||||
return;
|
||||
}
|
||||
startPlay();
|
||||
}
|
||||
|
||||
private void startPlay() {
|
||||
if (mAnimDataList != null && mAnimDataList.size() > 0) {
|
||||
mCurAnimPos = 0;
|
||||
AnimData animData = mAnimDataList.get(mCurAnimPos);
|
||||
mCurShowBmp = ImageUtil.getBitmap(getContext(), animData.filePath, mWidth, mHeight);
|
||||
invalidate();
|
||||
if (mListener != null) {
|
||||
mListener.onAnimChange(mCurAnimPos, mCurShowBmp);
|
||||
}
|
||||
checkIsPlayNext();
|
||||
}
|
||||
}
|
||||
|
||||
private void playNext(final int curAnimPosition) {
|
||||
Message msg = Message.obtain();
|
||||
msg.what = PROCESS_DELAY;
|
||||
msg.arg1 = curAnimPosition;
|
||||
mHandler.sendMessageDelayed(msg, mAnimTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
quit();
|
||||
}
|
||||
|
||||
private void quit() {
|
||||
mHasStarted = false;
|
||||
if (mProcessThread != null) {
|
||||
mProcessThread.clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
if (mProcessThread != null) {
|
||||
mProcessThread.setSize(w, h);
|
||||
}
|
||||
if (mHasStarted) {
|
||||
startPlay();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mHavePause = false;
|
||||
|
||||
public void pause() {
|
||||
mHavePause = true;
|
||||
mHandler.removeMessages(PROCESS_DELAY);
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
if (mHavePause && mHasStarted) {
|
||||
checkIsPlayNext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
//此 handleMessage 在主线程被调用
|
||||
switch (msg.what) {
|
||||
case PROCESS_ANIM_FINISH: {
|
||||
Bitmap bitmap = (Bitmap) msg.obj;
|
||||
if (bitmap != null) {
|
||||
if (mCurShowBmp != null) {
|
||||
mCurShowBmp.recycle();
|
||||
mCurShowBmp = null;
|
||||
}
|
||||
mCurShowBmp = bitmap;
|
||||
if (mListener != null) {
|
||||
mListener.onAnimChange(mCurAnimPos, bitmap);
|
||||
}
|
||||
invalidate();
|
||||
|
||||
}
|
||||
checkIsPlayNext();
|
||||
break;
|
||||
}
|
||||
case PROCESS_DELAY: {
|
||||
int curAnimPosition = msg.arg1;
|
||||
AnimData data = mAnimDataList.get(curAnimPosition);
|
||||
mProcessThread.processData(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkIsPlayNext() {
|
||||
mCurAnimPos++;
|
||||
if (mCurAnimPos >= mAnimDataList.size()) {
|
||||
if (mIsRepeat) {
|
||||
mCurAnimPos = 0;
|
||||
playNext(mCurAnimPos);
|
||||
} else {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimEnd();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
playNext(mCurAnimPos);
|
||||
}
|
||||
}
|
||||
|
||||
private AnimCallBack mListener;
|
||||
|
||||
public void setAnimCallBack(AnimCallBack callBack) {
|
||||
mListener = callBack;
|
||||
}
|
||||
|
||||
public interface AnimCallBack {
|
||||
void onAnimChange(int position, Bitmap bitmap);
|
||||
|
||||
void onAnimEnd();
|
||||
}
|
||||
|
||||
public static class AnimData {
|
||||
public Object filePath;
|
||||
}
|
||||
|
||||
public static class ProcessAnimThread {
|
||||
private HandlerThread mHandlerThread;
|
||||
private Handler mProcessHandler;
|
||||
private Handler mUiHandler;
|
||||
|
||||
private AnimData mCurAnimData;
|
||||
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private WeakReference<Context> mContext;
|
||||
|
||||
public ProcessAnimThread(Context context, Handler handler) {
|
||||
mUiHandler = handler;
|
||||
mContext = new WeakReference<Context>(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setSize(int width, int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mHandlerThread = new HandlerThread("process_anim_thread");
|
||||
mHandlerThread.start();
|
||||
|
||||
mProcessHandler = new Handler(mHandlerThread.getLooper(), new Handler.Callback() {
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
// 消息是在子线程 HandlerThread 里面被处理,所以这里的 handleMessage 在
|
||||
//子线程里被调用
|
||||
switch (msg.what) {
|
||||
case PROCESS_DATA: {
|
||||
AnimData animData = (AnimData) msg.obj;
|
||||
Bitmap bitmap = ImageUtil.getBitmap(mContext.get(), animData.filePath, mWidth, mHeight);
|
||||
if (bitmap != null) {
|
||||
Message finishMsg = Message.obtain();
|
||||
finishMsg.what = PROCESS_ANIM_FINISH;
|
||||
finishMsg.obj = bitmap;
|
||||
//消息处理完毕,使用主线程的 Handler 将消息发送到主线程
|
||||
mUiHandler.sendMessage(finishMsg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void processData(AnimData animData) {
|
||||
if (animData != null) {
|
||||
Message msg = Message.obtain();
|
||||
msg.what = PROCESS_DATA;
|
||||
msg.obj = animData;
|
||||
mProcessHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
mHandlerThread.quit();
|
||||
mHandlerThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.mogo.cloud.trafficlive.api.ITrafficCarLiveCallBack;
|
||||
import com.mogo.cloud.trafficlive.api.MoGoAiCloudTrafficLive;
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.mogo.map.location.MogoLocation;
|
||||
import com.mogo.module.v2x.R;
|
||||
import com.mogo.module.v2x.V2XServiceManager;
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
package com.mogo.module.v2x.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.customview.widget.ViewDragHelper;
|
||||
|
||||
import com.mogo.module.v2x.V2XConst;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/25 11:13 AM
|
||||
* desc :
|
||||
* version: 1.0
|
||||
*/
|
||||
public class GestureTopCloseLayout extends ConstraintLayout {
|
||||
private ViewDragHelper mViewDragHelper;
|
||||
|
||||
private ViewCloseListener mViewCloseListener;
|
||||
|
||||
public GestureTopCloseLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public GestureTopCloseLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public GestureTopCloseLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
|
||||
mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
|
||||
private int mTop;
|
||||
|
||||
@Override
|
||||
public boolean tryCaptureView(@NotNull View child, int pointerId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clampViewPositionVertical(@NotNull View child, int top, int dy) {
|
||||
final int bottomBound = getPaddingTop();
|
||||
return Math.min(top, bottomBound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clampViewPositionHorizontal(@NotNull View child, int left, int dx) {
|
||||
//取得左边界的坐标
|
||||
final int leftBound = getPaddingLeft();
|
||||
//取得右边界的坐标
|
||||
final int rightBound = getWidth() - child.getWidth() - child.getPaddingRight() - leftBound;
|
||||
//这个地方的含义就是 如果left的值 在leftbound和rightBound之间 那么就返回left
|
||||
//如果left的值 比 leftbound 还要小 那么就说明 超过了左边界 那我们只能返回给他左边界的值
|
||||
//如果right的值 比 rightbound 还要大 那么就说明 超过了右边界,那我们只能返回给他右边界的值
|
||||
return Math.min(Math.max(left, leftBound), rightBound);
|
||||
}
|
||||
|
||||
@Override //不重写该方法默认返回0,返回0时若还设置了点击事件则水平方向不能移动
|
||||
public int getViewHorizontalDragRange(@NotNull View child) {
|
||||
return getMeasuredWidth() - child.getMeasuredWidth();
|
||||
}
|
||||
|
||||
@Override //不重写该方法默认返回0,返回0时若还设置了点击事件则竖直方向不能移动
|
||||
public int getViewVerticalDragRange(@NotNull View child) {
|
||||
return getMeasuredHeight() - child.getMeasuredHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
|
||||
super.onViewPositionChanged(changedView, left, top, dx, dy);
|
||||
Logger.w(V2XConst.MODULE_NAME, "onViewPositionChanged==top=" + top +
|
||||
" changedView.getHeight()==" + changedView.getHeight());
|
||||
if (top < 0) {
|
||||
mTop = top;
|
||||
if (top <= -changedView.getHeight()) {
|
||||
mViewDragHelper.smoothSlideViewTo(changedView, 0, getPaddingTop());
|
||||
invalidate();
|
||||
if (mViewCloseListener != null) {
|
||||
mViewCloseListener.onClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//手指释放的时候回调
|
||||
@Override
|
||||
public void onViewReleased(View releasedChild, float xvel, float yvel) {
|
||||
Logger.w(V2XConst.MODULE_NAME, "onViewReleased==mTop=" + mTop + " getHeight=" + getHeight());
|
||||
if (mTop < 0) {
|
||||
mViewDragHelper.settleCapturedViewAt(0, -getHeight());
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return mViewDragHelper.shouldInterceptTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
mViewDragHelper.processTouchEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
if (mViewDragHelper.continueSettling(true)) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewCloseListener(ViewCloseListener mViewCloseListener) {
|
||||
this.mViewCloseListener = mViewCloseListener;
|
||||
}
|
||||
|
||||
public interface ViewCloseListener {
|
||||
void onClose();
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.mogo.module.v2x.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.mogo.module.v2x.R;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/27 2:08 PM
|
||||
* desc :
|
||||
* version: 1.0
|
||||
*/
|
||||
public class RoundConstraintLayout extends ConstraintLayout {
|
||||
|
||||
private float roundLayoutRadius = 14f;
|
||||
private Path roundPath;
|
||||
private RectF rectF;
|
||||
|
||||
public RoundConstraintLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RoundConstraintLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundLayout);
|
||||
roundLayoutRadius = typedArray.getDimensionPixelSize(R.styleable.RoundLayout_roundLayoutRadius, (int) roundLayoutRadius);
|
||||
typedArray.recycle();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public RoundConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
setWillNotDraw(false);//如果你继承的是ViewGroup,注意此行,否则draw方法是不会回调的;
|
||||
roundPath = new Path();
|
||||
rectF = new RectF();
|
||||
}
|
||||
|
||||
private void setRoundPath() {
|
||||
//添加一个圆角矩形到path中, 如果要实现任意形状的View, 只需要手动添加path就行
|
||||
roundPath.addRoundRect(rectF, roundLayoutRadius, roundLayoutRadius, Path.Direction.CW);
|
||||
}
|
||||
|
||||
|
||||
public void setRoundLayoutRadius(float roundLayoutRadius) {
|
||||
this.roundLayoutRadius = roundLayoutRadius;
|
||||
setRoundPath();
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
rectF.set(0f, 0f, getMeasuredWidth(), getMeasuredHeight());
|
||||
setRoundPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (roundLayoutRadius > 0f) {
|
||||
canvas.clipPath(roundPath);
|
||||
}
|
||||
super.draw(canvas);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package com.mogo.module.v2x.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.mogo.module.v2x.R;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/3/25 11:39 AM
|
||||
* desc :
|
||||
* version: 1.0
|
||||
*/
|
||||
public class RoundLayout extends RelativeLayout {
|
||||
private float roundLayoutRadius = 14f;
|
||||
private Path roundPath;
|
||||
private RectF rectF;
|
||||
|
||||
public RoundLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RoundLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RoundLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundLayout);
|
||||
roundLayoutRadius = typedArray.getDimensionPixelSize(R.styleable.RoundLayout_roundLayoutRadius, (int) roundLayoutRadius);
|
||||
typedArray.recycle();
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
setWillNotDraw(false);//如果你继承的是ViewGroup,注意此行,否则draw方法是不会回调的;
|
||||
roundPath = new Path();
|
||||
rectF = new RectF();
|
||||
}
|
||||
|
||||
private void setRoundPath() {
|
||||
//添加一个圆角矩形到path中, 如果要实现任意形状的View, 只需要手动添加path就行
|
||||
roundPath.addRoundRect(rectF, roundLayoutRadius, roundLayoutRadius, Path.Direction.CW);
|
||||
}
|
||||
|
||||
|
||||
public void setRoundLayoutRadius(float roundLayoutRadius) {
|
||||
this.roundLayoutRadius = roundLayoutRadius;
|
||||
setRoundPath();
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
rectF.set(0f, 0f, getMeasuredWidth(), getMeasuredHeight());
|
||||
setRoundPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (roundLayoutRadius > 0f) {
|
||||
canvas.clipPath(roundPath);
|
||||
}
|
||||
super.draw(canvas);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,590 +0,0 @@
|
||||
package com.mogo.module.v2x.view;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaPlayer.OnSeekCompleteListener;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.MediaController.MediaPlayerControl;
|
||||
|
||||
import com.mogo.module.v2x.R;
|
||||
import com.mogo.module.v2x.V2XConst;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
|
||||
|
||||
/**
|
||||
* Displays a video file. The VideoView class can load images from various
|
||||
* sources (such as resources or content providers), takes care of computing its
|
||||
* measurement from the video so that it can be used in any layout manager, and
|
||||
* provides various display options such as scaling and tinting.
|
||||
*/
|
||||
public class TextureVideoView extends TextureView implements MediaPlayerControl {
|
||||
private String TAG = "V2XModuleProvider";
|
||||
// settable by the client
|
||||
private Uri mUri;
|
||||
private Map<String, String> mHeaders;
|
||||
private int mDuration;
|
||||
|
||||
// all possible internal states
|
||||
private int mCurrentState = V2XConst.STATE_IDLE;
|
||||
private int mTargetState = mCurrentState, mTagetStateBackup = mCurrentState;
|
||||
private int mPrepareState = V2XConst.STATE_PREPARED;
|
||||
|
||||
// All the stuff we need for playing and showing a video
|
||||
private Surface mSurface = null;
|
||||
private MediaPlayer mMediaPlayer = null;
|
||||
private int mVideoWidth, mVideoHeight;
|
||||
|
||||
private OnCompletionListener mOnCompletionListener;
|
||||
private MediaPlayer.OnPreparedListener mOnPreparedListener;
|
||||
private int mCurrentBufferPercentage;
|
||||
private OnErrorListener mOnErrorListener;
|
||||
private MediaPlayer.OnInfoListener mOnInfoListener;
|
||||
private int mSeekWhenPrepared;
|
||||
private boolean isFocusLoss = true;
|
||||
private boolean isSuspendFromActivity = false;
|
||||
private int progressWhileSuspend = 0;
|
||||
public static final int MEDIA_INFO_VIDEO_NOT_SUPPORTED = 860;
|
||||
public static final int MEDIA_INFO_AUDIO_NOT_SUPPORTED = 862;
|
||||
|
||||
public TextureVideoView(Context context) {
|
||||
super(context);
|
||||
initVideoView();
|
||||
}
|
||||
|
||||
public TextureVideoView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, 0);
|
||||
initVideoView();
|
||||
}
|
||||
|
||||
public TextureVideoView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initVideoView();
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
||||
super.onInitializeAccessibilityEvent(event);
|
||||
event.setClassName(TextureVideoView.class.getName());
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
info.setClassName(TextureVideoView.class.getName());
|
||||
}
|
||||
|
||||
private void initVideoView() {
|
||||
mVideoWidth = 0;
|
||||
mVideoHeight = 0;
|
||||
setSurfaceTextureListener(mSurfaceTextureListener);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
mCurrentState = V2XConst.STATE_IDLE;
|
||||
mTargetState = V2XConst.STATE_IDLE;
|
||||
}
|
||||
|
||||
public boolean requestAudioFocus() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setVideoPath(String path) {
|
||||
setVideoURI(Uri.parse(path));
|
||||
}
|
||||
|
||||
public void setVideoURI(Uri uri) {
|
||||
setVideoURI(uri, null);
|
||||
}
|
||||
|
||||
public void setVideoURI(Uri uri, Map<String, String> headers) {
|
||||
if (uri == null) {
|
||||
Logger.i(MODULE_NAME, "setVideoURI--- uri = null");
|
||||
} else {
|
||||
Logger.i(MODULE_NAME, "setVideoURI--- uri = " + uri.getPath());
|
||||
}
|
||||
mUri = uri;
|
||||
mHeaders = headers;
|
||||
mSeekWhenPrepared = 0;
|
||||
isFocusLoss = !requestAudioFocus();
|
||||
openVideo();
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void stopPlayback() {
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.stop();
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer = null;
|
||||
mTargetState = mCurrentState = V2XConst.STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void openVideo() {
|
||||
Logger.i(MODULE_NAME, "openVideo");
|
||||
if (mUri == null) {
|
||||
Logger.i(MODULE_NAME, "mUri == null ");
|
||||
}
|
||||
if (mSurface == null) {
|
||||
Logger.i(MODULE_NAME, "mSurface == null ");
|
||||
}
|
||||
if (mUri == null || mSurface == null || isSuspendFromActivity) {
|
||||
Logger.i(MODULE_NAME, "isSuspendFromActivity = " + isSuspendFromActivity);
|
||||
return;
|
||||
}
|
||||
release(false);
|
||||
try {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mMediaPlayer.setOnPreparedListener(mPreparedListener);
|
||||
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
|
||||
mDuration = -1;
|
||||
mMediaPlayer.setOnCompletionListener(mCompletionListener);
|
||||
mMediaPlayer.setOnErrorListener(mErrorListener);
|
||||
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
|
||||
mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
|
||||
mMediaPlayer.setOnInfoListener(mInfoListener);
|
||||
mCurrentBufferPercentage = 0;
|
||||
mMediaPlayer.setDataSource(getContext(), mUri, mHeaders);
|
||||
if (mSurface != null) {
|
||||
/*
|
||||
Canvas mCanvas = mSurface.lockCanvas(new Rect());
|
||||
mCanvas.drawColor(Color.BLACK);
|
||||
mSurface.unlockCanvasAndPost(mCanvas);
|
||||
invalidate();
|
||||
*/
|
||||
mMediaPlayer.setSurface(mSurface);
|
||||
}
|
||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
mMediaPlayer.setScreenOnWhilePlaying(true);
|
||||
mMediaPlayer.setVolume(0, 0);
|
||||
mMediaPlayer.prepare();
|
||||
mPrepareState = mCurrentState = V2XConst.STATE_PREPARING;
|
||||
} catch (IOException | SecurityException | IllegalStateException | IllegalArgumentException ex) {
|
||||
ex.printStackTrace();
|
||||
onError();
|
||||
}
|
||||
}
|
||||
|
||||
private void onError() {
|
||||
mTargetState = mCurrentState = V2XConst.STATE_ERROR;
|
||||
if (mErrorListener != null)
|
||||
mErrorListener.onError(mMediaPlayer,
|
||||
MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||||
}
|
||||
|
||||
MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
|
||||
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
|
||||
mVideoWidth = mp.getVideoWidth();
|
||||
mVideoHeight = mp.getVideoHeight();
|
||||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||||
Logger.d(MODULE_NAME, "OnVideoSizeChangedListener mVideoWidth:" + " mVideoWidth:" + mVideoWidth + " mVideoHeight:" + mVideoHeight);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.OnPreparedListener");
|
||||
mPrepareState = mCurrentState = V2XConst.STATE_PREPARED;
|
||||
mVideoWidth = mp.getVideoWidth();
|
||||
mVideoHeight = mp.getVideoHeight();
|
||||
|
||||
int seekToPosition = mSeekWhenPrepared;
|
||||
// Logger.i(MODULE_NAME, "seekToPosition = " + seekToPosition);
|
||||
if (seekToPosition != 0) {
|
||||
seekTo(seekToPosition);
|
||||
}
|
||||
if (mTargetState == V2XConst.STATE_PLAYING) {
|
||||
start();
|
||||
}
|
||||
if (mOnPreparedListener != null) {
|
||||
mOnPreparedListener.onPrepared(mMediaPlayer);
|
||||
}
|
||||
mp.setOnInfoListener((mp1, what, extra) -> {
|
||||
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START)
|
||||
setBackgroundColor(Color.TRANSPARENT);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private OnCompletionListener mCompletionListener = new OnCompletionListener() {
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.OnCompletionListener");
|
||||
mTargetState = mCurrentState = V2XConst.STATE_PLAYBACK_COMPLETED;
|
||||
if (mOnCompletionListener != null) {
|
||||
mOnCompletionListener.onCompletion(mMediaPlayer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private OnSeekCompleteListener mSeekCompleteListener = mp -> {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.OnSeekCompleteListener");
|
||||
try {
|
||||
mCurrentState = mMediaPlayer.isPlaying() ? V2XConst.STATE_PLAYING : V2XConst.STATE_PAUSED;
|
||||
} catch (Exception e) {
|
||||
mCurrentState = V2XConst.STATE_PLAYING;
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
private OnErrorListener mErrorListener = new OnErrorListener() {
|
||||
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.onError");
|
||||
mTargetState = mPrepareState = mCurrentState = V2XConst.STATE_ERROR;
|
||||
if (mOnErrorListener != null) {
|
||||
mOnErrorListener.onError(mMediaPlayer, framework_err,
|
||||
impl_err);
|
||||
}
|
||||
release(false);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() {
|
||||
|
||||
@Override
|
||||
public boolean onInfo(MediaPlayer mp, int what, int extra) {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.OnInfoListener---what = " + what + ";extra = " + extra);
|
||||
int messageId = 0;
|
||||
if (what == MEDIA_INFO_VIDEO_NOT_SUPPORTED) {
|
||||
messageId = R.string.VideoView_info_text_video_not_supported;
|
||||
} else if (what == MEDIA_INFO_AUDIO_NOT_SUPPORTED) {
|
||||
messageId = R.string.file_not_support;
|
||||
}
|
||||
if (messageId != 0) {
|
||||
if (mOnInfoListener != null) {
|
||||
mOnInfoListener.onInfo(mp, what, extra);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
|
||||
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.OnBufferingUpdateListener");
|
||||
mCurrentBufferPercentage = percent;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when the media file is loaded and ready
|
||||
* to go.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
|
||||
mOnPreparedListener = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when the end of a media file has been
|
||||
* reached during playback.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setOnCompletionListener(OnCompletionListener l) {
|
||||
mOnCompletionListener = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when an error occurs during playback or
|
||||
* setup. If no listener is specified, or if the listener returned false,
|
||||
* VideoView will inform the user of any errors.
|
||||
*
|
||||
* @param l The callback that will be run
|
||||
*/
|
||||
public void setOnErrorListener(OnErrorListener l) {
|
||||
mOnErrorListener = l;
|
||||
}
|
||||
|
||||
public void setOnInfoListener(MediaPlayer.OnInfoListener l) {
|
||||
mOnInfoListener = l;
|
||||
}
|
||||
|
||||
SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||
Logger.i(MODULE_NAME, "onSurfaceTextureAvailable");
|
||||
mSurface = new Surface(surface);
|
||||
openVideo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
||||
Logger.d(MODULE_NAME, "onSurfaceTextureSizeChanged mVideoWidth:" + " mVideoWidth:" + mVideoWidth + " mVideoHeight:" + mVideoHeight);
|
||||
boolean isValidState = (mTargetState == V2XConst.STATE_PLAYING);
|
||||
boolean hasValidSize = (mVideoWidth == width && mVideoHeight == height);
|
||||
if (mMediaPlayer != null && isValidState && hasValidSize) {
|
||||
if (mSeekWhenPrepared != 0) {
|
||||
seekTo(mSeekWhenPrepared);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!isFocusLoss) start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||
Logger.i(MODULE_NAME, "onSurfaceTextureDestroyed");
|
||||
mSurface = null;
|
||||
release(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* release the media player in any state
|
||||
*/
|
||||
private void release(boolean cleartargetstate) {
|
||||
Logger.i(MODULE_NAME, "release ---cleartargetstate=" + cleartargetstate);
|
||||
mCurrentState = V2XConst.STATE_IDLE;
|
||||
|
||||
if (cleartargetstate) {
|
||||
mTargetState = V2XConst.STATE_IDLE;
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
|
||||
try {
|
||||
mMediaPlayer.stop();
|
||||
} catch (IllegalStateException e) {
|
||||
try {
|
||||
this.wait(1000);
|
||||
mMediaPlayer.stop();
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.release();// release会做reset
|
||||
}
|
||||
mMediaPlayer = null;
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
if (mMediaPlayer != null) {
|
||||
try {
|
||||
mMediaPlayer.stop();
|
||||
mMediaPlayer.reset();
|
||||
mMediaPlayer.release();
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
mMediaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPrepared() {
|
||||
return mPrepareState == V2XConst.STATE_PREPARED
|
||||
|| isSuspendFromActivity;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
Logger.i(MODULE_NAME, "TextureVideoView---start");
|
||||
if (isFocusLoss) {
|
||||
mTagetStateBackup = V2XConst.STATE_PLAYING;
|
||||
return;
|
||||
}
|
||||
//Logger.i(MODULE_NAME, "mCurrentState = " + mCurrentState);
|
||||
if (isInPlaybackState()) {
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.start");
|
||||
mMediaPlayer.start();
|
||||
mCurrentState = V2XConst.STATE_PLAYING;
|
||||
}
|
||||
mTargetState = V2XConst.STATE_PLAYING;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
Logger.i(MODULE_NAME, "TextureVideoView---pause");
|
||||
Logger.i(MODULE_NAME, "mCurrentState = " + mCurrentState);
|
||||
if (isInPlaybackState()) {
|
||||
if (mMediaPlayer.isPlaying()) {
|
||||
Logger.i(MODULE_NAME, " MediaPlayer.pause");
|
||||
mMediaPlayer.pause();
|
||||
mCurrentState = V2XConst.STATE_PAUSED;
|
||||
}
|
||||
}
|
||||
mTagetStateBackup = mTargetState = V2XConst.STATE_PAUSED;
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
Logger.i(MODULE_NAME, "TextureVideoView---suspend");
|
||||
if (!isSuspendFromActivity) {
|
||||
isSuspendFromActivity = true;
|
||||
if (mMediaPlayer != null) {
|
||||
if (isInPlaybackState()) {
|
||||
progressWhileSuspend = mMediaPlayer.getCurrentPosition();
|
||||
}
|
||||
}
|
||||
release(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
Logger.i(MODULE_NAME, "TextureVideoView---resume");
|
||||
isSuspendFromActivity = false;
|
||||
openVideo();
|
||||
seekTo(progressWhileSuspend);
|
||||
|
||||
if (mTagetStateBackup == V2XConst.STATE_IDLE)
|
||||
mTagetStateBackup = mTargetState;
|
||||
Logger.i(MODULE_NAME, "isFocusLoss = " + isFocusLoss);
|
||||
Logger.i(MODULE_NAME, "isInPlaybackState() = " + isInPlaybackState());
|
||||
if (isFocusLoss) {
|
||||
if (isInPlaybackState()) {
|
||||
if (mMediaPlayer.isPlaying()) {
|
||||
mMediaPlayer.pause();
|
||||
mCurrentState = V2XConst.STATE_PAUSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cache duration as mDuration for faster access
|
||||
public int getDuration() {
|
||||
if (isInPlaybackState()) {
|
||||
if (mDuration > 0) {
|
||||
return mDuration;
|
||||
}
|
||||
mDuration = mMediaPlayer.getDuration();
|
||||
return mDuration;
|
||||
}
|
||||
mDuration = -1;
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
if (isInPlaybackState()) {
|
||||
return mMediaPlayer.getCurrentPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void seekTo(int msec) {
|
||||
Logger.i(MODULE_NAME, "TextureVideoView---seekTo---msec = " + msec);
|
||||
if (isInPlaybackState() && mCurrentState != V2XConst.STATE_SEEKING
|
||||
&& msec > 0 && msec < getDuration()) {
|
||||
mCurrentState = V2XConst.STATE_SEEKING;
|
||||
|
||||
Logger.i(MODULE_NAME, "MediaPlayer.seekTo(msec) = " + msec);
|
||||
mMediaPlayer.seekTo(msec);
|
||||
mSeekWhenPrepared = 0;
|
||||
} else {
|
||||
mSeekWhenPrepared = msec;
|
||||
progressWhileSuspend = msec;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
return isInPlaybackState() && mMediaPlayer.isPlaying();
|
||||
}
|
||||
|
||||
public int getBufferPercentage() {
|
||||
if (mMediaPlayer != null) {
|
||||
return mCurrentBufferPercentage;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean isInPlaybackState() {
|
||||
return (mMediaPlayer != null && mCurrentState != V2XConst.STATE_ERROR
|
||||
&& mCurrentState != V2XConst.STATE_IDLE && mCurrentState != V2XConst.STATE_PREPARING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPause() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeekBackward() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeekForward() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getVideoPath() {
|
||||
if (mUri != null) {
|
||||
return mUri.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
|
||||
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
public boolean isPause() {
|
||||
return mTargetState == V2XConst.STATE_PAUSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAudioSessionId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getCurrentState() {
|
||||
Logger.i(MODULE_NAME, "mCurrentState == " + mCurrentState);
|
||||
return mCurrentState;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.mogo.module.common.entity.MarkerCarInfo;
|
||||
import com.mogo.module.v2x.R;
|
||||
import com.mogo.module.v2x.V2XServiceManager;
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.core.content.ContextCompat;
|
||||
import com.mogo.cloud.trafficlive.api.ITrafficIntersectionLiveCallBack;
|
||||
import com.mogo.cloud.trafficlive.api.MoGoAiCloudTrafficLive;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.mogo.map.location.MogoLocation;
|
||||
import com.mogo.module.common.entity.MarkerCarInfo;
|
||||
import com.mogo.module.v2x.R;
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.mogo.module.common.entity.MarkerCarInfo;
|
||||
import com.mogo.module.v2x.R;
|
||||
import com.mogo.module.v2x.utils.V2XUtils;
|
||||
|
||||
Reference in New Issue
Block a user