Commit 92fbe4a3 authored by linfeng's avatar linfeng

短视频

parent b28eace5
......@@ -108,8 +108,8 @@ dependencies {
annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0-rc1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
debugApi 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseApi 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
// api project(path: ':RvTravel')
......
......@@ -44,7 +44,7 @@
<color name="gray_FDB51C">#FDB51C</color>
<color name="gray_47E270">#47E270</color>
<color name="gray_B4B4B4">#B4B4B4</color>
<color name="gray_50171413">#50171413</color>
<!--end-->
</resources>
......@@ -63,6 +63,7 @@ dependencies {
api project(':component_utils')
api project(':component_control')
api project(':plugin_imcamera')
api project(':plugin_video')
}
......@@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application>
<activity android:name=".other.ShortVideoActivity"></activity>
<activity
android:name=".other.PatGeneratePosterActivity"
android:screenOrientation="portrait" />
......
......@@ -29,6 +29,7 @@ import com.xxfc.discovery.fragment.PatFragment;
import com.xxfc.discovery.fragment.QuestionAndAnswerFragment;
import com.xxfc.discovery.fragment.RecommendFragment;
import com.xxfc.discovery.fragment.ShortVideoFragment;
import com.xxfc.discovery.other.ShortVideoActivity;
import com.xxfc.discovery.popupwindow.AddDiscoveryContentPw;
import com.xxfc.discovery.presenter.DiscoveryPresenter;
import com.yuyife.okgo.OkGoUtil;
......@@ -203,14 +204,16 @@ public class DiscoveryFragment extends BaseFragment<DiscoveryPresenter> {
// showPopupWindow(ivDiscoveryContentAdd);
//判断是否已经登录
if (TextUtils.isEmpty(OkGoUtil.getToken())) {
ARouter.getInstance().build(Constance.ACTIVITY_URL_LOGINRV).navigation();
return;
}
ARouter.getInstance()
.build(Constance.ACTIVITY_URL_POSTPAT)
.navigation();
// if (TextUtils.isEmpty(OkGoUtil.getToken())) {
// ARouter.getInstance().build(Constance.ACTIVITY_URL_LOGINRV).navigation();
// return;
// }
//
// ARouter.getInstance()
// .build(Constance.ACTIVITY_URL_POSTPAT)
// .navigation();
startActivity(ShortVideoActivity.getIntent(_mActivity));
}
}
......
package com.xxfc.discovery.adapter;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ruiwenliu.wrapper.util.glide.GlideApp;
import com.ruiwenliu.wrapper.util.glide.GlideManager;
import com.xxfc.discovery.R;
import com.xxfc.discovery.bean.beam.VideoBean;
/**
* 短视频
*/
public class DiscoveryVideoAdapter extends BaseQuickAdapter<VideoBean, BaseViewHolder> {
public DiscoveryVideoAdapter() {
super(R.layout.rv_item_discovery_video);
}
@Override
protected void convert(BaseViewHolder helper, VideoBean item) {
if (item == null) {
return;
}
GlideApp.with(mContext)
.load(item.getThumb())
.placeholder(android.R.color.white)
.into((ImageView) helper.getView(R.id.thumb));
helper.addOnClickListener(R.id.ll_item_video_comment);
helper.addOnClickListener(R.id.ll_item_video_share);
}
}
package com.xxfc.discovery.adapter;
import android.widget.ImageView;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ruiwenliu.wrapper.util.glide.GlideApp;
import com.xxfc.discovery.R;
import com.xxfc.discovery.bean.beam.VideoBean;
/**
* 短视频评论
*/
public class DiscoveryVideoCommentAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public DiscoveryVideoCommentAdapter() {
super(R.layout.rv_item_discovery_video_comment);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
if (item == null) {
return;
}
}
}
package com.xxfc.discovery.bean.beam;
public class VideoBean {
private String title;
private String url;
private String thumb;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getThumb() {
return thumb;
}
public void setThumb(String thumb) {
this.thumb = thumb;
}
public VideoBean(String title, String thumb, String url) {
this.title = title;
this.url = url;
this.thumb = thumb;
}
}
package com.xxfc.discovery.dialog;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import com.frame.rv.config.RvFrameConfig;
import com.ruiwenliu.wrapper.dialog.BaseDialog;
import com.ruiwenliu.wrapper.util.ViewHolder;
import com.rv.component.utils.DisplayUtil;
import com.xxfc.discovery.R;
import com.xxfc.discovery.adapter.DiscoveryVideoCommentAdapter;
import com.xxfc.discovery.api.DiscoveryApi;
import com.xxfc.discovery.bean.DiscoveryIMTokenBean;
import com.yuyife.okgo.OkGoUtil;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 视频评论
*/
public class DiscoveryVideoDialog extends BaseDialog {
private final Context context;
private DiscoveryVideoCommentAdapter commentAdapter;
public DiscoveryVideoDialog(@NonNull Context context) {
super(context);
this.context = context;
setDialogParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtil.dip2px(context, 450), Gravity.BOTTOM);
}
@Override
public void helper(ViewHolder helper) {
super.helper(helper);
RecyclerView recyclerView = helper.getView(R.id.rv_video_comment);
commentAdapter = new DiscoveryVideoCommentAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(getDialogContext()));
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(commentAdapter);
helper.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TrillCommentInputDialog trillCommentInputDialog = new TrillCommentInputDialog(context, new TrillCommentInputDialog.OnSendCommentListener() {
@Override
public void sendComment(String str) {
}
});
Window window = trillCommentInputDialog.getWindow();
if (window != null) {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);// 软键盘弹起
trillCommentInputDialog.show();
}
}
}, R.id.ll_item_comment);
initData();
}
private void initData() {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 8; i++) {
list.add("3333");
}
commentAdapter.addData(list);
}
@Override
public int getViewLayout() {
return R.layout.dialog_discovery_video;
}
}
package com.xxfc.discovery.other;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.dueeeke.videoplayer.player.VideoView;
import com.ruiwenliu.wrapper.base.BaseBean;
import com.ruiwenliu.wrapper.base.BaseStatusActivity;
import com.ruiwenliu.wrapper.statusbar.StatusBarUtil;
import com.ruiwenliu.wrapper.util.ViewHolder;
import com.ruiwenliu.wrapper.util.glide.GlideApp;
import com.ruiwenliu.wrapper.weight.TitleView;
import com.xxfc.discovery.R;
import com.xxfc.discovery.R2;
import com.xxfc.discovery.adapter.DiscoveryVideoAdapter;
import com.xxfc.discovery.bean.beam.DataUtil;
import com.xxfc.discovery.bean.beam.VideoBean;
import com.xxfc.discovery.dialog.DiscoveryVideoDialog;
import com.xxfc.discovery.presenter.DiscoveryPresenter;
import com.xxfc.discovery.widget.OnViewPagerListener;
import com.xxfc.discovery.widget.TikTokController;
import com.xxfc.discovery.widget.ViewPagerLayoutManager;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
/**
* 短视频
*/
public class ShortVideoActivity extends BaseStatusActivity<DiscoveryPresenter> {
@BindView(R2.id.rv_short_video)
RecyclerView rvShortVideo;
@BindView(R2.id.iv_item_video_play)
ImageView ivVideoPlay;
private VideoView mVideoView;
private TikTokController mTikTokController;
private int mCurrentPosition;
private List<VideoBean> mVideoList;
public static Intent getIntent(Context context) {
return new Intent(context, ShortVideoActivity.class);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StatusBarUtil.setRootViewFitsSystemWindows(mActivity, false);
mVideoView = new VideoView(this);
mVideoView.setLooping(true);
mTikTokController = new TikTokController(this);
mVideoView.setVideoController(mTikTokController);
DiscoveryVideoAdapter tikTokAdapter = new DiscoveryVideoAdapter();
ViewPagerLayoutManager layoutManager = new ViewPagerLayoutManager(this, OrientationHelper.VERTICAL);
rvShortVideo.setLayoutManager(layoutManager);
rvShortVideo.setAdapter(tikTokAdapter);
layoutManager.setOnViewPagerListener(new OnViewPagerListener() {
@Override
public void onInitComplete() {
//自动播放第一条
startPlay(0);
}
@Override
public void onPageRelease(boolean isNext, int position) {
if (mCurrentPosition == position) {
mVideoView.release();
}
}
@Override
public void onPageSelected(int position, boolean isBottom) {
if (mCurrentPosition == position) return;
startPlay(position);
mCurrentPosition = position;
}
});
tikTokAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
int id = view.getId();
if (id == R.id.ll_item_video_comment) {
showCommentDialog();
} else if (id == R.id.ll_item_video_share) {
}
}
});
mVideoList = DataUtil.getTikTokVideoList();
tikTokAdapter.addData(mVideoList);
}
/**
* 评论
*/
private void showCommentDialog() {
new DiscoveryVideoDialog(mActivity) {
@Override
public void helper(ViewHolder helper) {
super.helper(helper);
}
}.show();
}
@Override
protected int setLayout() {
return R.layout.activity_short_video;
}
@Override
protected void initView(Bundle savedInstanceState, TitleView titleView, Intent intent) {
showTitle(false);
}
private void startPlay(int position) {
View itemView = rvShortVideo.getChildAt(0);
FrameLayout frameLayout = itemView.findViewById(R.id.container);
GlideApp.with(this)
.load(mVideoList.get(position).getThumb())
.placeholder(android.R.color.white)
.into(mTikTokController.getThumb());
ViewParent parent = mVideoView.getParent();
if (parent instanceof FrameLayout) {
((FrameLayout) parent).removeView(mVideoView);
}
frameLayout.addView(mVideoView);
mVideoView.setUrl(mVideoList.get(position).getUrl());
mVideoView.setScreenScale(VideoView.SCREEN_SCALE_CENTER_CROP);
mVideoView.start();
}
@Override
public void onShowResult(int requestType, BaseBean result) {
}
@Override
public void onPause() {
super.onPause();
mVideoView.pause();
}
@Override
public void onResume() {
super.onResume();
mVideoView.resume();
}
@Override
public void onDestroy() {
super.onDestroy();
mVideoView.release();
}
@OnClick(R2.id.iv_item_video_play)
public void onViewClicked(View v) {
int id = v.getId();
if (id == R.id.iv_item_video_play) {
// if (mVideoView.isPlaying()) {
// mVideoView.pause();
// ivVideoPlay.animate().alpha(1.0f).start();
// } else {
// mVideoView.resume();
// ivVideoPlay.animate().alpha(0f).start();
// }
}
}
}
package com.xxfc.discovery.widget;
public interface OnViewPagerListener {
/*初始化完成*/
void onInitComplete();
/*释放的监听*/
void onPageRelease(boolean isNext, int position);
/*选中的监听以及判断是否滑动到底部*/
void onPageSelected(int position, boolean isBottom);
}
package com.xxfc.discovery.widget;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.dueeeke.videoplayer.controller.BaseVideoController;
import com.dueeeke.videoplayer.player.VideoView;
import com.dueeeke.videoplayer.util.L;
import com.xxfc.discovery.R;
public class TikTokController extends BaseVideoController {
private ImageView thumb;
public TikTokController(@NonNull Context context) {
super(context);
}
public TikTokController(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TikTokController(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected int getLayoutId() {
return R.layout.layout_tiktok_controller;
}
@Override
protected void initView() {
super.initView();
thumb = mControllerView.findViewById(R.id.iv_thumb);
}
@Override
public void setPlayState(int playState) {
super.setPlayState(playState);
switch (playState) {
case VideoView.STATE_IDLE:
L.e("STATE_IDLE");
thumb.setVisibility(VISIBLE);
break;
case VideoView.STATE_PLAYING:
L.e("STATE_PLAYING");
thumb.setVisibility(GONE);
break;
case VideoView.STATE_PREPARED:
L.e("STATE_PREPARED");
break;
}
}
public ImageView getThumb() {
return thumb;
}
}
package com.xxfc.discovery.widget;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.PagerSnapHelper;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class ViewPagerLayoutManager extends LinearLayoutManager {
private static final String TAG = "ViewPagerLayoutManager";
private PagerSnapHelper mPagerSnapHelper;
private OnViewPagerListener mOnViewPagerListener;
private RecyclerView mRecyclerView;
private int mDrift;//位移,用来判断移动方向
public ViewPagerLayoutManager(Context context, int orientation) {
super(context, orientation, false);
init();
}
public ViewPagerLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
init();
}
private void init() {
mPagerSnapHelper = new PagerSnapHelper();
}
@Override
public void onAttachedToWindow(RecyclerView view) {
super.onAttachedToWindow(view);
mPagerSnapHelper.attachToRecyclerView(view);
this.mRecyclerView = view;
mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
//
}
/**
* 滑动状态的改变
* 缓慢拖拽-> SCROLL_STATE_DRAGGING
* 快速滚动-> SCROLL_STATE_SETTLING
* 空闲状态-> SCROLL_STATE_IDLE
* @param state
*/
@Override
public void onScrollStateChanged(int state) {
switch (state) {
case RecyclerView.SCROLL_STATE_IDLE:
View viewIdle = mPagerSnapHelper.findSnapView(this);
int positionIdle = getPosition(viewIdle);
if (mOnViewPagerListener != null && getChildCount() == 1) {
mOnViewPagerListener.onPageSelected(positionIdle,positionIdle == getItemCount() - 1);
}
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
View viewDrag = mPagerSnapHelper.findSnapView(this);
int positionDrag = getPosition(viewDrag);
break;
case RecyclerView.SCROLL_STATE_SETTLING:
View viewSettling = mPagerSnapHelper.findSnapView(this);
int positionSettling = getPosition(viewSettling);
break;
}
}
/**
* 监听竖直方向的相对偏移量
* @param dy
* @param recycler
* @param state
* @return
*/
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
this.mDrift = dy;
return super.scrollVerticallyBy(dy, recycler, state);
}
/**
* 监听水平方向的相对偏移量
* @param dx
* @param recycler
* @param state
* @return
*/
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
this.mDrift = dx;
return super.scrollHorizontallyBy(dx, recycler, state);
}
/**
* 设置监听
* @param listener
*/
public void setOnViewPagerListener(OnViewPagerListener listener){
this.mOnViewPagerListener = listener;
}
private RecyclerView.OnChildAttachStateChangeListener mChildAttachStateChangeListener = new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
if (mOnViewPagerListener != null && getChildCount() == 1) {
mOnViewPagerListener.onInitComplete();
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
if (mDrift >= 0){
if (mOnViewPagerListener != null) mOnViewPagerListener.onPageRelease(true,getPosition(view));
}else {
if (mOnViewPagerListener != null) mOnViewPagerListener.onPageRelease(false,getPosition(view));
}
}
};
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="50dp" />
<solid android:color="@color/gray_50171413" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".other.ShortVideoActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_short_video"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_item_video_play"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:alpha="0"
android:clickable="true"
android:focusable="true"
android:src="@drawable/icon_live_profile_paly"
android:tint="#f2f2f2" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWrite"
android:orientation="vertical"
tools:ignore="MissingDefaultResource">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/size_10"
android:layout_marginBottom="@dimen/size_10">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="全部评论45条"
android:textColor="@color/textGray"
android:textSize="@dimen/text_14" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="@dimen/size_30"
android:layout_height="@dimen/size_30"
android:layout_alignParentRight="true"
android:layout_marginTop="@dimen/size_10"
android:layout_marginRight="@dimen/size_10"
android:padding="@dimen/size_5"
android:src="@drawable/common_btn_close" />
</RelativeLayout>
<include layout="@layout/common_line" />
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_video_comment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v7.widget.RecyclerView>
<LinearLayout
android:id="@+id/ll_item_comment"
android:layout_width="match_parent"
android:layout_height="@dimen/size_60"
android:layout_marginLeft="@dimen/size_15"
android:layout_marginRight="@dimen/size_15"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="@dimen/size_40"
android:layout_weight="1"
android:background="@drawable/shape_rv_textview_home_search"
android:gravity="center_vertical"
android:paddingLeft="@dimen/size_15"
android:text="说点什么吧..."
android:textColor="@color/colorGray"
android:textSize="@dimen/text_14" />
<TextView
android:layout_width="@dimen/size_60"
android:layout_height="@dimen/size_40"
android:layout_marginLeft="@dimen/size_15"
android:background="@drawable/shape_rv_bg_yellow"
android:gravity="center"
android:text="评论"
android:textColor="@color/colorWrite"
android:textSize="@dimen/text_14" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="@dimen/size_20"
android:layout_marginBottom="@dimen/size_70"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:layout_width="@dimen/size_60"
android:layout_height="@dimen/size_60"
android:src="@drawable/aa_dis11" />
<LinearLayout
android:layout_width="@dimen/size_45"
android:layout_height="@dimen/size_45"
android:layout_marginTop="@dimen/size_30"
android:background="@drawable/shape_rv_bg_black_half"
android:gravity="center">
<ImageView
android:layout_width="@dimen/size_20"
android:layout_height="@dimen/size_20"
android:src="@drawable/icon_discover_video_likeun" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/size_3"
android:text="1542"
android:textColor="@color/colorWrite"
android:textSize="@dimen/text_12" />
<LinearLayout
android:id="@+id/ll_item_video_comment"
android:layout_width="@dimen/size_45"
android:layout_height="@dimen/size_45"
android:layout_marginTop="@dimen/size_15"
android:background="@drawable/shape_rv_bg_black_half"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="@dimen/size_20"
android:layout_height="@dimen/size_20"
android:src="@drawable/icon_discover_video_commentun" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/size_3"
android:text="1542"
android:textColor="@color/colorWrite"
android:textSize="@dimen/text_12" />
<LinearLayout
android:id="@+id/ll_item_video_share"
android:layout_width="@dimen/size_45"
android:layout_height="@dimen/size_45"
android:layout_marginTop="@dimen/size_15"
android:gravity="center"
android:background="@drawable/shape_rv_bg_black_half"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/size_20"
android:layout_height="@dimen/size_20"
android:src="@drawable/icon_discover_video_share" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/size_3"
android:text="1542"
android:textColor="@color/colorWrite"
android:textSize="@dimen/text_12" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="@dimen/size_15"
android:layout_marginBottom="@dimen/size_15"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="中蒙界湖-贝尔湖"
android:textColor="@color/colorWrite"
android:textSize="@dimen/text_14" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/size_10"
android:drawableLeft="@drawable/icon_discover_video_location"
android:drawablePadding="@dimen/size_5"
android:text="呼伦贝尔湖西南部边缘"
android:textColor="@color/colorWrite"
android:textSize="@dimen/text_10" />
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/size_15"
android:paddingRight="@dimen/size_15">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/size_15"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/size_25"
android:layout_height="@dimen/size_25"
android:src="@drawable/aa_dis11" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/size_10"
android:layout_weight="1"
android:text="房车旅行家Rose"
android:textColor="@color/colorMain"
android:textSize="@dimen/text_14" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2019-06-05 12:00"
android:textColor="@color/textLightGrey"
android:textSize="@dimen/text_10" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/size_10"
android:layout_marginBottom="@dimen/size_10"
android:text="住在里面真的是面朝大海,春暖花开呀 很安静,可以听到鸟儿的叫
声 浪花拍打沙滩的声音 柔软 浪花拍打沙滩的声音 柔软的沙滩"
android:textColor="@color/textGray"
android:textSize="@dimen/text_12" />
<include layout="@layout/common_line"/>
</LinearLayout>
\ No newline at end of file
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\sdk/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 *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dueeeke.videoplayer">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>
package com.dueeeke.videoplayer.controller;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import com.dueeeke.videoplayer.R;
import com.dueeeke.videoplayer.player.VideoView;
import com.dueeeke.videoplayer.player.VideoViewManager;
import com.dueeeke.videoplayer.util.PlayerUtils;
import com.dueeeke.videoplayer.widget.StatusView;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;
/**
* 控制器基类
* Created by Devlin_n on 2017/4/12.
*/
public abstract class BaseVideoController extends FrameLayout {
protected View mControllerView;//控制器视图
protected MediaPlayerControl mMediaPlayer;//播放器
protected boolean mShowing;//控制器是否处于显示状态
protected boolean mIsLocked;
protected int mDefaultTimeout = 4000;
private StringBuilder mFormatBuilder;
private Formatter mFormatter;
protected int mCurrentPlayState;
protected StatusView mStatusView;
public BaseVideoController(@NonNull Context context) {
this(context, null);
}
public BaseVideoController(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseVideoController(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
protected void initView() {
mControllerView = LayoutInflater.from(getContext()).inflate(getLayoutId(), this);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
mStatusView = new StatusView(getContext());
setClickable(true);
setFocusable(true);
}
/**
* 设置控制器布局文件,子类必须实现
*/
protected abstract int getLayoutId();
/**
* 显示
*/
public void show() {
}
/**
* 隐藏
*/
public void hide() {
}
public void setPlayState(int playState) {
mCurrentPlayState = playState;
hideStatusView();
if (playState == VideoView.STATE_ERROR) {
mStatusView.setMessage(getResources().getString(R.string.dkplayer_error_message));
mStatusView.setButtonTextAndAction(getResources().getString(R.string.dkplayer_retry), new OnClickListener() {
@Override
public void onClick(View v) {
hideStatusView();
mMediaPlayer.replay(false);
}
});
this.addView(mStatusView, 0);
}
}
public void showStatusView() {
this.removeView(mStatusView);
mStatusView.setMessage(getResources().getString(R.string.dkplayer_wifi_tip));
mStatusView.setButtonTextAndAction(getResources().getString(R.string.dkplayer_continue_play), new OnClickListener() {
@Override
public void onClick(View v) {
hideStatusView();
VideoViewManager.instance().setPlayOnMobileNetwork(true);
mMediaPlayer.start();
}
});
this.addView(mStatusView);
}
public void hideStatusView() {
this.removeView(mStatusView);
}
public void setPlayerState(int playerState) {
}
protected void doPauseResume() {
if (mCurrentPlayState == VideoView.STATE_BUFFERING) return;
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
} else {
mMediaPlayer.start();
}
}
/**
* 横竖屏切换
*/
protected void doStartStopFullScreen() {
Activity activity = PlayerUtils.scanForActivity(getContext());
if (activity == null) return;
if (mMediaPlayer.isFullScreen()) {
mMediaPlayer.stopFullScreen();
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mMediaPlayer.startFullScreen();
}
}
protected Runnable mShowProgress = new Runnable() {
@Override
public void run() {
int pos = setProgress();
if (mMediaPlayer.isPlaying()) {
postDelayed(mShowProgress, 1000 - (pos % 1000));
}
}
};
protected final Runnable mFadeOut = new Runnable() {
@Override
public void run() {
hide();
}
};
protected int setProgress() {
return 0;
}
/**
* 获取当前系统时间
*/
protected String getCurrentSystemTime() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
Date date = new Date();
return simpleDateFormat.format(date);
}
protected String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
post(mShowProgress);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeCallbacks(mShowProgress);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
if (visibility == VISIBLE) {
post(mShowProgress);
}
}
/**
* 改变返回键逻辑,用于activity
*/
public boolean onBackPressed() {
return false;
}
public void setMediaPlayer(MediaPlayerControl mediaPlayer) {
this.mMediaPlayer = mediaPlayer;
}
}
package com.dueeeke.videoplayer.controller;
import android.content.Context;
import android.media.AudioManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.dueeeke.videoplayer.R;
import com.dueeeke.videoplayer.util.PlayerUtils;
import com.dueeeke.videoplayer.widget.CenterView;
/**
* 包含手势操作的VideoController
* Created by xinyu on 2018/1/6.
*/
public abstract class GestureVideoController extends BaseVideoController{
protected GestureDetector mGestureDetector;
protected boolean mIsGestureEnabled;
protected CenterView mCenterView;
protected AudioManager mAudioManager;
public GestureVideoController(@NonNull Context context) {
super(context);
}
public GestureVideoController(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public GestureVideoController(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void initView() {
super.initView();
mCenterView = new CenterView(getContext());
mCenterView.setVisibility(GONE);
addView(mCenterView);
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mGestureDetector = new GestureDetector(getContext(), new MyGestureListener());
this.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
});
}
protected int mStreamVolume;
protected float mBrightness;
protected int mPosition;
protected boolean mNeedSeek;
protected class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
private boolean mFirstTouch;
private boolean mChangePosition;
private boolean mChangeBrightness;
private boolean mChangeVolume;
@Override
public boolean onDown(MotionEvent e) {
if (!mIsGestureEnabled || PlayerUtils.isEdge(getContext(), e)) return super.onDown(e);
mStreamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
mBrightness = PlayerUtils.scanForActivity(getContext()).getWindow().getAttributes().screenBrightness;
mFirstTouch = true;
mChangePosition = false;
mChangeBrightness = false;
mChangeVolume = false;
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (mShowing) {
hide();
} else {
show();
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!mIsGestureEnabled || PlayerUtils.isEdge(getContext(), e1)) return super.onScroll(e1, e2, distanceX, distanceY);
float deltaX = e1.getX() - e2.getX();
float deltaY = e1.getY() - e2.getY();
if (mFirstTouch) {
mChangePosition = Math.abs(distanceX) >= Math.abs(distanceY);
if (!mChangePosition) {
if (e2.getX() > PlayerUtils.getScreenWidth(getContext(), true) / 2) {
mChangeVolume = true;
} else {
mChangeBrightness = true;
}
}
mFirstTouch = false;
}
if (mChangePosition) {
slideToChangePosition(deltaX);
} else if (mChangeBrightness) {
slideToChangeBrightness(deltaY);
} else if (mChangeVolume) {
slideToChangeVolume(deltaY);
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (!mIsLocked) doPauseResume();
return true;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean detectedUp = event.getAction() == MotionEvent.ACTION_UP;
if (!mGestureDetector.onTouchEvent(event) && detectedUp) {
if (mCenterView.getVisibility() == VISIBLE) {
mCenterView.setVisibility(GONE);
}
if (mNeedSeek) {
mMediaPlayer.seekTo(mPosition);
mNeedSeek = false;
}
}
return super.onTouchEvent(event);
}
protected void slideToChangePosition(float deltaX) {
mCenterView.setVisibility(VISIBLE);
hide();
mCenterView.setProVisibility(View.GONE);
deltaX = -deltaX;
int width = getMeasuredWidth();
int duration = (int) mMediaPlayer.getDuration();
int currentPosition = (int) mMediaPlayer.getCurrentPosition();
int position = (int) (deltaX / width * 120000 + currentPosition);
if (position > currentPosition) {
mCenterView.setIcon(R.drawable.dkplayer_ic_action_fast_forward);
} else {
mCenterView.setIcon(R.drawable.dkplayer_ic_action_fast_rewind);
}
if (position > duration) position = duration;
if (position < 0) position = 0;
mPosition = position;
mCenterView.setTextView(stringForTime(position) + "/" + stringForTime(duration));
mNeedSeek = true;
}
protected void slideToChangeBrightness(float deltaY) {
mCenterView.setVisibility(VISIBLE);
hide();
mCenterView.setProVisibility(View.VISIBLE);
Window window = PlayerUtils.scanForActivity(getContext()).getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
mCenterView.setIcon(R.drawable.dkplayer_ic_action_brightness);
int height = getMeasuredHeight();
if (mBrightness == -1.0f) mBrightness = 0.5f;
float brightness = deltaY * 2 / height * 1.0f + mBrightness;
if (brightness < 0) {
brightness = 0f;
}
if (brightness > 1.0f) brightness = 1.0f;
int percent = (int) (brightness * 100);
mCenterView.setTextView(percent + "%");
mCenterView.setProPercent(percent);
attributes.screenBrightness = brightness;
window.setAttributes(attributes);
}
protected void slideToChangeVolume(float deltaY) {
mCenterView.setVisibility(VISIBLE);
hide();
mCenterView.setProVisibility(View.VISIBLE);
int streamMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
int height = getMeasuredHeight();
float deltaV = deltaY * 2 / height * streamMaxVolume;
float index = mStreamVolume + deltaV;
if (index > streamMaxVolume) index = streamMaxVolume;
if (index < 0) {
mCenterView.setIcon(R.drawable.dkplayer_ic_action_volume_off);
index = 0;
} else {
mCenterView.setIcon(R.drawable.dkplayer_ic_action_volume_up);
}
int percent = (int) (index / streamMaxVolume * 100);
mCenterView.setTextView(percent + "%");
mCenterView.setProPercent(percent);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) index, 0);
}
}
package com.dueeeke.videoplayer.controller;
import android.graphics.Bitmap;
public interface MediaPlayerControl {
void start();
void pause();
long getDuration();
long getCurrentPosition();
void seekTo(long pos);
boolean isPlaying();
int getBufferedPercentage();
void startFullScreen();
void stopFullScreen();
boolean isFullScreen();
void setMute(boolean isMute);
boolean isMute();
void setLock(boolean isLocked);
void setScreenScale(int screenScale);
void setSpeed(float speed);
long getTcpSpeed();
void replay(boolean resetPosition);
void setMirrorRotation(boolean enable);
Bitmap doScreenShot();
int[] getVideoSize();
void setRotation(float rotation);
void startTinyScreen();
void stopTinyScreen();
boolean isTinyScreen();
}
\ No newline at end of file
package com.dueeeke.videoplayer.listener;
public interface OnVideoViewStateChangeListener {
void onPlayerStateChanged(int playerState);
void onPlayStateChanged(int playState);
}
package com.dueeeke.videoplayer.listener;
/**
* Created by xinyu on 2017/12/21.
*/
public interface PlayerEventListener {
void onError();
void onCompletion();
void onInfo(int what, int extra);
void onPrepared();
void onVideoSizeChanged(int width, int height);
}
package com.dueeeke.videoplayer.player;
import android.content.res.AssetFileDescriptor;
import android.view.Surface;
import android.view.SurfaceHolder;
import com.dueeeke.videoplayer.listener.PlayerEventListener;
import java.util.List;
import java.util.Map;
/**
* Created by Devlin_n on 2017/12/21.
*/
public abstract class AbstractPlayer {
/**
* 开始渲染视频画面
*/
public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3;
/**
* 缓冲开始
*/
public static final int MEDIA_INFO_BUFFERING_START = 701;
/**
* 缓冲结束
*/
public static final int MEDIA_INFO_BUFFERING_END = 702;
/**
* 视频旋转信息
*/
public static final int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;
/**
* 播放器事件回调
*/
protected PlayerEventListener mPlayerEventListener;
/**
* 初始化播放器实例
*/
public abstract void initPlayer();
/**
* 设置播放地址
* @param path 播放地址
* @param headers 播放地址请求头
*/
public abstract void setDataSource(String path, Map<String, String> headers);
/**
* 用于播放raw和asset里面的视频文件
*/
public abstract void setDataSource(AssetFileDescriptor fd);
public abstract void setDataSource(List<String> paths);
/**
* 播放
*/
public abstract void start();
/**
* 暂停
*/
public abstract void pause();
/**
* 停止
*/
public abstract void stop();
/**
* 准备开始播放(异步)
*/
public abstract void prepareAsync();
/**
* 重置播放器
*/
public abstract void reset();
/**
* 是否正在播放
*/
public abstract boolean isPlaying();
/**
* 调整进度
*/
public abstract void seekTo(long time);
/**
* 释放播放器
*/
public abstract void release();
/**
* 获取当前播放的位置
*/
public abstract long getCurrentPosition();
/**
* 获取视频总时长
*/
public abstract long getDuration();
/**
* 获取缓冲百分比
*/
public abstract int getBufferedPercentage();
/**
* 设置渲染视频的View,主要用于TextureView
*/
public abstract void setSurface(Surface surface);
/**
* 设置渲染视频的View,主要用于SurfaceView
*/
public abstract void setDisplay(SurfaceHolder holder);
/**
* 设置音量
*/
public abstract void setVolume(float v1, float v2);
/**
* 设置是否循环播放
*/
public abstract void setLooping(boolean isLooping);
/**
* 设置硬解码
*/
public abstract void setEnableMediaCodec(boolean isEnable);
/**
* 设置其他播放配置
*/
public abstract void setOptions();
/**
* 设置播放速度
*/
public abstract void setSpeed(float speed);
/**
* 获取当前缓冲的网速
*/
public abstract long getTcpSpeed();
/**
* 绑定VideoView
*/
public void setPlayerEventListener(PlayerEventListener playerEventListener) {
this.mPlayerEventListener = playerEventListener;
}
}
package com.dueeeke.videoplayer.player;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.Surface;
import android.view.SurfaceHolder;
import java.util.List;
import java.util.Map;
public class AndroidMediaPlayer extends AbstractPlayer {
protected MediaPlayer mMediaPlayer;
private boolean isLooping;
protected Context mAppContext;
private int mBufferedPercent;
public AndroidMediaPlayer(Context context) {
mAppContext = context.getApplicationContext();
}
@Override
public void initPlayer() {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnErrorListener(onErrorListener);
mMediaPlayer.setOnCompletionListener(onCompletionListener);
mMediaPlayer.setOnInfoListener(onInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(onBufferingUpdateListener);
mMediaPlayer.setOnPreparedListener(onPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener);
}
@Override
public void setDataSource(String path, Map<String, String> headers) {
try {
mMediaPlayer.setDataSource(mAppContext, Uri.parse(path), headers);
} catch (Exception e) {
mPlayerEventListener.onError();
}
}
@Override
public void setDataSource(AssetFileDescriptor fd) {
try {
mMediaPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
} catch (Exception e) {
mPlayerEventListener.onError();
}
}
@Override
public void setDataSource(List<String> paths) {
}
@Override
public void start() {
try {
mMediaPlayer.start();
} catch (IllegalStateException e) {
mPlayerEventListener.onError();
}
}
@Override
public void pause() {
try {
mMediaPlayer.pause();
} catch (IllegalStateException e) {
mPlayerEventListener.onError();
}
}
@Override
public void stop() {
try {
mMediaPlayer.stop();
} catch (IllegalStateException e) {
mPlayerEventListener.onError();
}
}
@Override
public void prepareAsync() {
try {
mMediaPlayer.prepareAsync();
} catch (IllegalStateException e) {
mPlayerEventListener.onError();
}
}
@Override
public void reset() {
mMediaPlayer.release();
initPlayer();
mMediaPlayer.setVolume(1, 1);
mMediaPlayer.setLooping(isLooping);
}
@Override
public boolean isPlaying() {
return mMediaPlayer.isPlaying();
}
@Override
public void seekTo(long time) {
try {
mMediaPlayer.seekTo((int) time);
} catch (IllegalStateException e) {
mPlayerEventListener.onError();
}
}
@Override
public void release() {
new Thread() {
@Override
public void run() {
try {
mMediaPlayer.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public long getCurrentPosition() {
return mMediaPlayer.getCurrentPosition();
}
@Override
public long getDuration() {
return mMediaPlayer.getDuration();
}
@Override
public int getBufferedPercentage() {
return mBufferedPercent;
}
@Override
public void setSurface(Surface surface) {
mMediaPlayer.setSurface(surface);
}
@Override
public void setDisplay(SurfaceHolder holder) {
mMediaPlayer.setDisplay(holder);
}
@Override
public void setVolume(float v1, float v2) {
mMediaPlayer.setVolume(v1, v2);
}
@Override
public void setLooping(boolean isLooping) {
this.isLooping = isLooping;
mMediaPlayer.setLooping(isLooping);
}
@Override
public void setEnableMediaCodec(boolean isEnable) {
// no support
}
@Override
public void setOptions() {
// no support
}
@Override
public void setSpeed(float speed) {
// no support
}
@Override
public long getTcpSpeed() {
// no support
return 0;
}
private MediaPlayer.OnErrorListener onErrorListener = new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mPlayerEventListener.onError();
return true;
}
};
private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mPlayerEventListener.onCompletion();
}
};
private MediaPlayer.OnInfoListener onInfoListener = new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
mPlayerEventListener.onInfo(what, extra);
return true;
}
};
private MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
mBufferedPercent = percent;
}
};
private MediaPlayer.OnPreparedListener onPreparedListener = new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mPlayerEventListener.onPrepared();
mMediaPlayer.start();
}
};
private MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
int videoWidth = mp.getVideoWidth();
int videoHeight = mp.getVideoHeight();
if (videoWidth != 0 && videoHeight != 0) {
mPlayerEventListener.onVideoSizeChanged(videoWidth, videoHeight);
}
}
};
}
package com.dueeeke.videoplayer.player;
import android.content.Context;
public class AndroidMediaPlayerFactory extends PlayerFactory {
private Context mContext;
public AndroidMediaPlayerFactory(Context context) {
mContext = context.getApplicationContext();
}
public static AndroidMediaPlayerFactory create(Context context) {
return new AndroidMediaPlayerFactory(context);
}
@Override
public AbstractPlayer createPlayer() {
return new AndroidMediaPlayer(mContext);
}
}
package com.dueeeke.videoplayer.player;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
/**
* 由于IjkPlayer已经不再更新,后续不再基于IjkPlayer进行开发,而是将本框架打造成一个通用的播放器框架
* 保留此类目的仅为向下兼容,后续版本将会移除
* @deprecated 使用 {@link VideoView} 代替
*/
@Deprecated
public class IjkVideoView extends VideoView {
public IjkVideoView(@NonNull Context context) {
super(context);
}
public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
\ No newline at end of file
package com.dueeeke.videoplayer.player;
public abstract class PlayerFactory {
public abstract AbstractPlayer createPlayer();
}
package com.dueeeke.videoplayer.player;
public abstract class ProgressManager {
public abstract void saveProgress(String url, long progress);
public abstract long getSavedProgress(String url);
}
package com.dueeeke.videoplayer.player;
import android.support.annotation.Nullable;
/**
* 播放器全局配置
*/
public class VideoViewConfig {
public static Builder newBuilder() {
return new Builder();
}
public final boolean mPlayOnMobileNetwork;
public final boolean mEnableMediaCodec;
public final boolean mUsingSurfaceView;
public final boolean mAutoRotate;
public final boolean mEnableAudioFocus;
public final boolean mEnableParallelPlay;
public final boolean mIsEnableLog;
public final ProgressManager mProgressManager;
public final PlayerFactory mPlayerFactory;
public final int mScreenScaleType;
private VideoViewConfig(Builder builder) {
mIsEnableLog = builder.mIsEnableLog;
mAutoRotate = builder.mAutoRotate;
mUsingSurfaceView = builder.mUsingSurfaceView;
mPlayOnMobileNetwork = builder.mPlayOnMobileNetwork;
mEnableMediaCodec = builder.mEnableMediaCodec;
mEnableAudioFocus = builder.mEnableAudioFocus;
mProgressManager = builder.mProgressManager;
mEnableParallelPlay = builder.mEnableParallelPlay;
mPlayerFactory = builder.mPlayerFactory;
mScreenScaleType = builder.mScreenScaleType;
}
public final static class Builder {
private boolean mIsEnableLog;
private boolean mPlayOnMobileNetwork;
private boolean mUsingSurfaceView;
private boolean mAutoRotate;
private boolean mEnableMediaCodec;
private boolean mEnableAudioFocus = true;
private boolean mEnableParallelPlay;
private ProgressManager mProgressManager;
private PlayerFactory mPlayerFactory;
private int mScreenScaleType;
/**
* 是否通过重力感应切换全屏/半屏播放器, 默认不开启
*/
public Builder setAutoRotate(boolean autoRotate) {
mAutoRotate = autoRotate;
return this;
}
/**
* 是否启用SurfaceView,默认不启用
*/
public Builder setUsingSurfaceView(boolean usingSurfaceView) {
mUsingSurfaceView = usingSurfaceView;
return this;
}
/**
* 是否使用MediaCodec进行解码(硬解码),默认不开启,使用软解
*/
public Builder setEnableMediaCodec(boolean enableMediaCodec) {
mEnableMediaCodec = enableMediaCodec;
return this;
}
/**
* 在移动环境下调用start()后是否继续播放,默认不继续播放
*/
public Builder setPlayOnMobileNetwork(boolean playOnMobileNetwork) {
mPlayOnMobileNetwork = playOnMobileNetwork;
return this;
}
/**
* 是否开启AudioFocus监听, 默认开启
*/
public Builder setEnableAudioFocus(boolean enableAudioFocus) {
mEnableAudioFocus = enableAudioFocus;
return this;
}
/**
* 设置进度管理器,用于保存播放进度
*/
public Builder setProgressManager(@Nullable ProgressManager progressManager) {
mProgressManager = progressManager;
return this;
}
/**
* 支持多开
*/
public Builder setEnableParallelPlay(boolean enableParallelPlay) {
mEnableParallelPlay = enableParallelPlay;
return this;
}
/**
* 是否打印日志
*/
public Builder setLogEnabled(boolean enableLog) {
mIsEnableLog = enableLog;
return this;
}
/**
* 自定义播放核心
*/
public Builder setPlayerFactory(PlayerFactory playerFactory) {
mPlayerFactory = playerFactory;
return this;
}
/**
* 设置视频比例
*/
public Builder setScreenScale(int screenScaleType) {
mScreenScaleType = screenScaleType;
return this;
}
public VideoViewConfig build() {
return new VideoViewConfig(this);
}
}
}
package com.dueeeke.videoplayer.player;
import java.util.ArrayList;
import java.util.List;
/**
* 视频播放器管理器,管理当前正在播放的VideoView,以及播放器配置
*/
public class VideoViewManager {
/**
* 当前正在播放的VideoView
*/
private List<VideoView> mVideoViews = new ArrayList<>();
private boolean mPlayOnMobileNetwork;
private VideoViewManager() {
mPlayOnMobileNetwork = getConfig().mPlayOnMobileNetwork;
}
private static VideoViewManager sInstance;
private static VideoViewConfig sConfig;
public static void setConfig(VideoViewConfig config) {
if (sConfig == null) {
synchronized (VideoViewConfig.class) {
if (sConfig == null) {
sConfig = config == null ? VideoViewConfig.newBuilder().build() : config;
}
}
}
}
public static VideoViewConfig getConfig() {
setConfig(null);
return sConfig;
}
public boolean playOnMobileNetwork() {
return mPlayOnMobileNetwork;
}
public void setPlayOnMobileNetwork(boolean playOnMobileNetwork) {
mPlayOnMobileNetwork = playOnMobileNetwork;
}
public static VideoViewManager instance() {
if (sInstance == null) {
synchronized (VideoViewManager.class) {
if (sInstance == null) {
sInstance = new VideoViewManager();
}
}
}
return sInstance;
}
public void addVideoView(VideoView videoView) {
mVideoViews.add(videoView);
}
public void removeVideoView(VideoView videoView) {
mVideoViews.remove(videoView);
}
public List<VideoView> getVideoViews() {
return mVideoViews;
}
@Deprecated
public void releaseVideoPlayer() {
release();
}
public void pause() {
for (int i = 0; i < mVideoViews.size(); i++) {
VideoView vv = mVideoViews.get(i);
if (vv != null) {
vv.pause();
}
}
}
public void resume() {
for (int i = 0; i < mVideoViews.size(); i++) {
VideoView vv = mVideoViews.get(i);
if (vv != null) {
vv.resume();
}
}
}
public void release() {
for (int i = 0; i < mVideoViews.size(); i++) {
VideoView vv = mVideoViews.get(i);
if (vv != null) {
vv.release();
i--;
}
}
}
public boolean onBackPressed() {
for (int i = 0; i < mVideoViews.size(); i++) {
VideoView vv = mVideoViews.get(i);
if (vv != null) {
boolean b = vv.onBackPressed();
if (b) return true;
}
}
return false;
}
}
package com.dueeeke.videoplayer.util;
import android.util.Log;
import com.dueeeke.videoplayer.player.VideoViewManager;
/**
* 日志类
* Created by Devlin_n on 2017/6/5.
*/
public class L {
private static final String TAG = "DKPlayer";
private static boolean isDebug = VideoViewManager.getConfig().mIsEnableLog;
public static void d(String msg) {
if (isDebug) {
Log.d(TAG, msg);
}
}
public static void e(String msg) {
if (isDebug) {
Log.e(TAG, msg);
}
}
public static void i(String msg) {
if (isDebug) {
Log.i(TAG, msg);
}
}
public static void w(Throwable e) {
if (isDebug) {
Log.w(TAG, e);
}
}
public static void setDebug(boolean isDebug) {
L.isDebug = isDebug;
}
}
package com.dueeeke.videoplayer.util;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.graphics.Point;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.util.TypedValue;
import android.view.Display;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.WindowManager;
/**
* 播放器相关工具类
* Created by Devlin_n on 2017/4/10.
*/
public class PlayerUtils {
/**
* 获取状态栏高度
*/
public static double getStatusBarHeight(Context context) {
int statusBarHeight = 0;
//获取status_bar_height资源的ID
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
//根据资源ID获取响应的尺寸值
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
/**
* 获取NavigationBar的高度
*/
public static int getNavigationBarHeight(Context context) {
if (!hasNavigationBar(context)) {
return 0;
}
Resources resources = context.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height",
"dimen", "android");
//获取NavigationBar的高度
return resources.getDimensionPixelSize(resourceId);
}
/**
* 是否存在NavigationBar
*/
public static boolean hasNavigationBar(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Display display = getWindowManager(context).getDefaultDisplay();
Point size = new Point();
Point realSize = new Point();
display.getSize(size);
display.getRealSize(realSize);
return realSize.x != size.x || realSize.y != size.y;
} else {
boolean menu = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
return !(menu || back);
}
}
/**
* 获取屏幕宽度
*/
public static int getScreenWidth(Context context, boolean isIncludeNav) {
if (isIncludeNav) {
return context.getResources().getDisplayMetrics().widthPixels + getNavigationBarHeight(context);
} else {
return context.getResources().getDisplayMetrics().widthPixels;
}
}
/**
* 获取屏幕高度
*/
public static int getScreenHeight(Context context, boolean isIncludeNav) {
if (isIncludeNav) {
return context.getResources().getDisplayMetrics().heightPixels + getNavigationBarHeight(context);
} else {
return context.getResources().getDisplayMetrics().heightPixels;
}
}
/**
* 获取Activity
*/
public static Activity scanForActivity(Context context) {
return context == null ? null : (context instanceof Activity ? (Activity) context : (context instanceof ContextWrapper ? scanForActivity(((ContextWrapper) context).getBaseContext()) : null));
}
/**
* dp转为px
*/
public static int dp2px(Context context, float dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
}
/**
* sp转为px
*/
public static int sp2px(Context context, float dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dpValue, context.getResources().getDisplayMetrics());
}
/**
* 如果WindowManager还未创建,则创建一个新的WindowManager返回。否则返回当前已创建的WindowManager。
*/
public static WindowManager getWindowManager(Context context) {
return (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
/**
* 边缘检测
*/
public static boolean isEdge(Context context, MotionEvent e) {
int edgeSize = dp2px(context, 40);
return e.getRawX() < edgeSize
|| e.getRawX() > getScreenWidth(context, true) - edgeSize
|| e.getRawY() < edgeSize
|| e.getRawY() > getScreenHeight(context, true) - edgeSize;
}
public static final int NO_NETWORK = 0;
public static final int NETWORK_CLOSED = 1;
public static final int NETWORK_ETHERNET = 2;
public static final int NETWORK_WIFI = 3;
public static final int NETWORK_MOBILE = 4;
public static final int NETWORK_UNKNOWN = -1;
/**
* 判断当前网络类型-1为未知网络0为没有网络连接1网络断开或关闭2为以太网3为WiFi4为2G5为3G6为4G
*/
public static int getNetworkType(Context context) {
//改为context.getApplicationContext(),防止在Android 6.0上发生内存泄漏
ConnectivityManager connectMgr = (ConnectivityManager) context.getApplicationContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectMgr == null) {
return NO_NETWORK;
}
NetworkInfo networkInfo = connectMgr.getActiveNetworkInfo();
if (networkInfo == null) {
// 没有任何网络
return NO_NETWORK;
}
if (!networkInfo.isConnected()) {
// 网络断开或关闭
return NETWORK_CLOSED;
}
if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
// 以太网网络
return NETWORK_ETHERNET;
} else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
// wifi网络,当激活时,默认情况下,所有的数据流量将使用此连接
return NETWORK_WIFI;
} else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
// 移动数据连接,不能与连接共存,如果wifi打开,则自动关闭
switch (networkInfo.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
// 2G网络
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
// 3G网络
case TelephonyManager.NETWORK_TYPE_LTE:
// 4G网络
return NETWORK_MOBILE;
}
}
// 未知网络
return NETWORK_UNKNOWN;
}
}
package com.dueeeke.videoplayer.widget;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.dueeeke.videoplayer.R;
/**
* 显示亮度,音量,进度
* Created by Devlin_n on 2017/4/17.
*/
public class CenterView extends LinearLayout {
private ImageView ivIcon;
private TextView tvPercent;
private ProgressBar proPercent;
public CenterView(Context context) {
super(context);
init();
}
private void init() {
setGravity(Gravity.CENTER);
View view = LayoutInflater.from(getContext()).inflate(R.layout.dkplayer_layout_center_window, this);
ivIcon = view.findViewById(R.id.iv_icon);
tvPercent = view.findViewById(R.id.tv_percent);
proPercent = view.findViewById(R.id.pro_percent);
}
public void setIcon(int icon) {
if (ivIcon != null) ivIcon.setImageResource(icon);
}
public void setTextView(String text) {
if (tvPercent != null) tvPercent.setText(text);
}
public void setProPercent(int percent) {
if (proPercent != null) proPercent.setProgress(percent);
}
public void setProVisibility(int visibility) {
if (proPercent != null) proPercent.setVisibility(visibility);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (visibility != VISIBLE) {
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.dkplayer_anim_center_view);
this.startAnimation(animation);
}
}
}
package com.dueeeke.videoplayer.widget;
import android.graphics.Bitmap;
import android.view.View;
public interface IRenderView {
/**
* 设置视频宽高
* @param videoWidth 宽
* @param videoHeight 高
*/
void setVideoSize(int videoWidth, int videoHeight);
/**
* 设置视频旋转角度
* @param degree 角度值
*/
void setVideoRotation(int degree);
/**
* 设置screen scale type
* @param scaleType 类型
*/
void setScaleType(int scaleType);
/**
* 获取真实的RenderView
*/
View getView();
/**
* 截图
*/
Bitmap doScreenShot();
/**
* 释放资源
*/
void release();
}
\ No newline at end of file
package com.dueeeke.videoplayer.widget;
import android.view.View;
import com.dueeeke.videoplayer.player.VideoView;
public class MeasureHelper {
private int mVideoWidth;
private int mVideoHeight;
private int mCurrentScreenScale;
private int mVideoRotationDegree;
public void setVideoRotation(int videoRotationDegree) {
mVideoRotationDegree = videoRotationDegree;
}
public void setVideoSize(int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
}
public void setScreenScale(int screenScale) {
mCurrentScreenScale = screenScale;
}
public int[] doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) { // 软解码时处理旋转信息,交换宽高
widthMeasureSpec = widthMeasureSpec + heightMeasureSpec;
heightMeasureSpec = widthMeasureSpec - heightMeasureSpec;
widthMeasureSpec = widthMeasureSpec - heightMeasureSpec;
}
int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
//如果设置了比例
switch (mCurrentScreenScale) {
case VideoView.SCREEN_SCALE_ORIGINAL:
width = mVideoWidth;
height = mVideoHeight;
break;
case VideoView.SCREEN_SCALE_16_9:
if (height > width / 16 * 9) {
height = width / 16 * 9;
} else {
width = height / 9 * 16;
}
break;
case VideoView.SCREEN_SCALE_4_3:
if (height > width / 4 * 3) {
height = width / 4 * 3;
} else {
width = height / 3 * 4;
}
// Log.d("@@@@", "onMeasure 4:3 : width" + width + " height:" + height);
break;
case VideoView.SCREEN_SCALE_MATCH_PARENT:
width = widthMeasureSpec;
height = heightMeasureSpec;
break;
case VideoView.SCREEN_SCALE_CENTER_CROP:
if (mVideoWidth > 0 && mVideoHeight > 0) {
if (mVideoWidth * height > width * mVideoHeight) {
width = height * mVideoWidth / mVideoHeight;
} else {
height = width * mVideoHeight / mVideoWidth;
}
}
break;
case VideoView.SCREEN_SCALE_DEFAULT:
default:
if (mVideoWidth > 0 && mVideoHeight > 0) {
int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecSize;
height = heightSpecSize;
// for compatibility, we adjust size based on aspect ratio
if (mVideoWidth * height < width * mVideoHeight) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else if (mVideoWidth * height > width * mVideoHeight) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
}
} else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
// couldn't match aspect ratio within the constraints
height = heightSpecSize;
}
} else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
// couldn't match aspect ratio within the constraints
width = widthSpecSize;
}
} else {
// neither the width nor the height are fixed, try to use actual video size
width = mVideoWidth;
height = mVideoHeight;
if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
}
if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
}
}
} else {
// no size yet, just adopt the given spec sizes
}
break;
}
return new int[]{width, height};
}
}
package com.dueeeke.videoplayer.widget;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.dueeeke.videoplayer.R;
/**
* 错误提示,网络提示
* Created by Devlin_n on 2017/4/13.
*/
public class StatusView extends LinearLayout {
private TextView tvMessage;
private TextView btnAction;
private float downX;
private float downY;
public StatusView(Context context) {
this(context, null);
}
public StatusView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
View root = LayoutInflater.from(getContext()).inflate(R.layout.dkplayer_layout_status_view, this);
tvMessage = root.findViewById(R.id.message);
btnAction = root.findViewById(R.id.status_btn);
this.setBackgroundResource(android.R.color.black);
setClickable(true);
}
public void setMessage(String msg) {
if (tvMessage != null) tvMessage.setText(msg);
}
public void setButtonTextAndAction(String text, OnClickListener listener) {
if (btnAction != null) {
btnAction.setText(text);
btnAction.setOnClickListener(listener);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
downY = ev.getY();
// True if the child does not want the parent to intercept touch events.
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
float absDeltaX = Math.abs(ev.getX() - downX);
float absDeltaY = Math.abs(ev.getY() - downY);
if (absDeltaX > ViewConfiguration.get(getContext()).getScaledTouchSlop() ||
absDeltaY > ViewConfiguration.get(getContext()).getScaledTouchSlop()) {
getParent().requestDisallowInterceptTouchEvent(false);
}
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
}
package com.dueeeke.videoplayer.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.support.annotation.NonNull;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import com.dueeeke.videoplayer.player.AbstractPlayer;
@SuppressLint("ViewConstructor")
public class SurfaceRenderView extends SurfaceView implements IRenderView, SurfaceHolder.Callback {
private MeasureHelper mMeasureHelper;
private AbstractPlayer mMediaPlayer;
public SurfaceRenderView(Context context, @NonNull AbstractPlayer player) {
super(context);
mMediaPlayer = player;
initView();
}
private void initView() {
mMeasureHelper = new MeasureHelper();
SurfaceHolder surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setFormat(PixelFormat.RGBA_8888);
}
@Override
public void setVideoSize(int videoWidth, int videoHeight) {
if (videoWidth > 0 && videoHeight > 0) {
mMeasureHelper.setVideoSize(videoWidth, videoHeight);
requestLayout();
}
}
@Override
public void setVideoRotation(int degree) {
mMeasureHelper.setVideoRotation(degree);
setRotation(degree);
}
@Override
public void setScaleType(int scaleType) {
mMeasureHelper.setScreenScale(scaleType);
requestLayout();
}
@Override
public View getView() {
return this;
}
@Override
public Bitmap doScreenShot() {
return null;
}
@Override
public void release() {
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int[] measuredSize = mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measuredSize[0], measuredSize[1]);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
\ No newline at end of file
package com.dueeeke.videoplayer.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.support.annotation.NonNull;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import com.dueeeke.videoplayer.player.AbstractPlayer;
@SuppressLint("ViewConstructor")
public class TextureRenderView extends TextureView implements IRenderView, TextureView.SurfaceTextureListener {
private MeasureHelper mMeasureHelper;
private SurfaceTexture mSurfaceTexture;
private AbstractPlayer mMediaPlayer;
private Surface mSurface;
public TextureRenderView(Context context, @NonNull AbstractPlayer player) {
super(context);
mMediaPlayer = player;
initView();
}
private void initView() {
mMeasureHelper = new MeasureHelper();
setSurfaceTextureListener(this);
}
@Override
public void setVideoSize(int videoWidth, int videoHeight) {
if (videoWidth > 0 && videoHeight > 0) {
mMeasureHelper.setVideoSize(videoWidth, videoHeight);
requestLayout();
}
}
@Override
public void setVideoRotation(int degree) {
mMeasureHelper.setVideoRotation(degree);
setRotation(degree);
}
@Override
public void setScaleType(int scaleType) {
mMeasureHelper.setScreenScale(scaleType);
requestLayout();
}
@Override
public View getView() {
return this;
}
@Override
public Bitmap doScreenShot() {
return getBitmap();
}
@Override
public void release() {
if (mSurface != null)
mSurface.release();
if (mSurfaceTexture != null)
mSurfaceTexture.release();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int[] measuredSize = mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measuredSize[0], measuredSize[1]);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
if (mSurfaceTexture != null) {
setSurfaceTexture(mSurfaceTexture);
} else {
mSurfaceTexture = surfaceTexture;
mSurface = new Surface(surfaceTexture);
mMediaPlayer.setSurface(mSurface);
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1"
android:toAlpha="0"
android:duration="300">
</alpha>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#cc999999"/>
<size android:height="1dp"/>
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<solid android:color="@android:color/white"/>
<size android:height="1dp"/>
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="@color/dkplayer_theme_color"/>
<size android:height="1dp"/>
</shape>
</clip>
</item>
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/dkplayer_theme_color"/>
<corners android:radius="30dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="160dp"
android:layout_height="120dp"
android:background="#96000000"
android:gravity="center">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="36dp"
android:layout_height="36dp"
tools:src="@drawable/dkplayer_ic_action_volume_up"/>
<TextView
android:id="@+id/tv_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="@android:color/white"
android:textSize="14sp"
tools:text="100"/>
<ProgressBar
android:id="@+id/pro_percent"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="100dp"
android:layout_height="3dp"
android:max="100"
android:progressDrawable="@drawable/dkplayer_layer_progress_bar" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="@android:color/black">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:textColor="@android:color/white"
tools:text="You are currently using the mobile network, and continuing to play will consume traffic" />
<TextView
android:id="@+id/status_btn"
android:layout_width="wrap_content"
android:layout_height="26dp"
android:background="@drawable/dkplayer_shape_status_view_btn"
android:gravity="center"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="@android:color/white"
tools:text="继续播放" />
</LinearLayout>
</FrameLayout>
\ No newline at end of file
<resources>
<string name="dkplayer_error_message">Something went wrong, please try again later</string>
<string name="dkplayer_retry"> Retry </string>
<string name="dkplayer_continue_play">Continue playing</string>
<string name="dkplayer_wifi_tip">You are currently using the mobile network, and continuing to play will consume traffic</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="VideoView">
<attr name="looping" format="boolean"/>
<attr name="autoRotate" format="boolean"/>
<attr name="enableAudioFocus" format="boolean"/>
<attr name="enableMediaCodec" format="boolean"/>
<attr name="usingSurfaceView" format="boolean"/>
<attr name="enableParallelPlay" format="boolean"/>
<attr name="screenScaleType" format="dimension">
<enum name="type_default" value="0"/>
<enum name="type_16_9" value="1"/>
<enum name="type_4_3" value="2"/>
<enum name="type_match_parent" value="3"/>
<enum name="type_original" value="4"/>
<enum name="type_center_crop" value="5"/>
</attr>
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="dkplayer_theme_color">#39C5BB</color>
</resources>
\ No newline at end of file
<resources>
<string name="dkplayer_error_message">出了点小问题,请稍后重试</string>
<string name="dkplayer_retry"> 重 试 </string>
<string name="dkplayer_continue_play">继续播放</string>
<string name="dkplayer_wifi_tip">您正在使用移动网络,继续播放将消耗流量</string>
</resources>
include ':RvFrame', ':plugin_carpurchase', ':plugin_poster'
include ':RvFrame'
include ':RvClient'
include ':RvWrapper'
include ':module_home'
......@@ -27,4 +27,7 @@ include ':plugin_coupon'
include ':plugin_share'
include ':plugin_points'
include ':plugin_imcamera'
include ':plugin_wallet'
\ No newline at end of file
include ':plugin_wallet'
include ':plugin_video'
include '::plugin_carpurchase'
include '::plugin_poster'
\ No newline at end of file
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