package com.netease.nim.uikit.session.activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.netease.nim.uikit.R;
import com.netease.nim.uikit.common.activity.UI;
import com.netease.nim.uikit.common.util.file.FileUtil;
import com.netease.nim.uikit.common.util.sys.TimeUtil;
import com.netease.nim.uikit.model.ToolBarOptions;
import com.netease.nimlib.sdk.AbortableFuture;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.MsgServiceObserve;
import com.netease.nimlib.sdk.msg.attachment.VideoAttachment;
import com.netease.nimlib.sdk.msg.constant.AttachStatusEnum;
import com.netease.nimlib.sdk.msg.model.AttachmentProgress;
import com.netease.nimlib.sdk.msg.model.IMMessage;
/**
* 视频播放界面
* <p/>
* Created by huangjun on 2015/4/11.
*/
public class WatchVideoActivity extends UI implements Callback {
public static final String INTENT_EXTRA_DATA = "EXTRA_DATA";
// player
private MediaPlayer mediaPlayer;
// context
private Handler handlerTimes = new Handler();
private ActionBar actionBar;
private IMMessage message;
// view
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private View videoIcon;
private View downloadLayout;
private View downloadProgressBackground;
private View downloadProgressForeground;
private TextView downloadProgressText;
protected TextView fileInfoTextView;
private TextView playTimeTextView;
// state
private boolean isSurfaceCreated = false;
protected String videoFilePath;
protected long videoLength = 0;
private float lastPercent;
private int playState = PLAY_STATE_STOP;
private final static int PLAY_STATE_PLAYING = 1;
private final static int PLAY_STATE_STOP = 2;
private final static int PLAY_STATE_PAUSE = 3;
// download control
private boolean downloading;
private ImageView downloadBtn;
private AbortableFuture downloadFuture;
public static void start(Context context, IMMessage message) {
Intent intent = new Intent();
intent.putExtra(WatchVideoActivity.INTENT_EXTRA_DATA, message);
intent.setClass(context, WatchVideoActivity.class);
context.startActivity(intent);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nim_watch_video_activity);
ToolBarOptions options = new ToolBarOptions();
options.navigateId = R.drawable.nim_actionbar_white_back_icon;
setToolBar(R.id.toolbar, options);
parseIntent();
findViews();
showVideoInfo();
registerObservers(true);
download();
}
public void onResume() {
super.onResume();
mediaPlayer = new MediaPlayer();
if (isSurfaceCreated) {
play();
}
}
@Override
public void onPause() {
super.onPause();
stopMediaPlayer();
}
@Override
public void onBackPressed() {
stopDownload();
super.onBackPressed();
}
@Override
protected void onDestroy() {
super.onDestroy();
registerObservers(false);
}
private void parseIntent() {
message = (IMMessage) getIntent().getSerializableExtra(INTENT_EXTRA_DATA);
}
private void findViews() {
downloadLayout = findViewById(R.id.layoutDownload);
downloadProgressBackground = findViewById(R.id.downloadProgressBackground);
downloadProgressForeground = findViewById(R.id.downloadProgressForeground);
downloadProgressText = (TextView) findViewById(R.id.downloadProgressText);
videoIcon = findViewById(R.id.videoIcon);
surfaceView = (SurfaceView) findViewById(R.id.videoView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.addCallback(this);
playTimeTextView = (TextView) findViewById(R.id.lblVideoTimes);
playTimeTextView.setVisibility(View.INVISIBLE);
fileInfoTextView = (TextView) findViewById(R.id.lblVideoFileInfo);
playTimeTextView.setVisibility(View.INVISIBLE);
downloadBtn = (ImageView) findViewById(R.id.control_download_btn);
downloadBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (downloading) {
stopDownload();
} else {
download();
}
downloadBtn.setImageResource(downloading ? R.drawable.nim_icon_download_pause : R.drawable.nim_icon_download_resume);
}
});
actionBar = getSupportActionBar();
}
private void initVideoSize() {
if (mediaPlayer == null) {
return;
}
// 视频宽高
int width = mediaPlayer.getVideoWidth();
int height = mediaPlayer.getVideoHeight();
if (width <= 0 || height <= 0) {
return;
}
// 屏幕宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenWidth = dm.widthPixels;
int screenHeight = dm.heightPixels;
int videoRatio = width / height;
int screenRatio = screenWidth / screenHeight;
if (screenRatio > videoRatio) {
int newHeight = screenHeight;
int newWidth = screenHeight * width / height;
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
newWidth, newHeight);
int margin = (screenWidth - newWidth) / 2;
layoutParams.setMargins(margin, 0, margin, 0);
surfaceView.setLayoutParams(layoutParams);
} else {
int newWidth = screenWidth;
int newHeight = screenWidth * height / width;
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
newWidth, newHeight);
int margin = (screenHeight - newHeight) / 2;
layoutParams.setMargins(0, margin, 0, margin);
surfaceView.setLayoutParams(layoutParams);
}
}
/**
* ****************************** MediaPlayer Start ********************************
*/
private void stopMediaPlayer() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
actionBar.show();
}
}
/**
* 处理视频播放时间
*/
private Runnable timeRunnable = new Runnable() {
public void run() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
playState = PLAY_STATE_PLAYING;
if (videoLength <= 0) {
playTimeTextView.setVisibility(View.INVISIBLE);
} else {
// 由于mediaPlayer取到的时间不统一,采用消息体中的时间
int leftTimes = (int) (videoLength * 1000 - mediaPlayer.getCurrentPosition());
if (leftTimes < 0) {
leftTimes = 0;
}
playTimeTextView.setVisibility(View.VISIBLE);
long seconds = TimeUtil.getSecondsByMilliseconds(leftTimes);
playTimeTextView.setText(TimeUtil.secToTime((int) seconds));
handlerTimes.postDelayed(this, 1000);
}
}
}
};
protected void pauseVideo() {
videoIcon.setVisibility(View.VISIBLE);
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
handlerTimes.removeCallbacks(timeRunnable);
playState = PLAY_STATE_PAUSE;
actionBar.show();
}
}
protected void resumeVideo() {
videoIcon.setVisibility(View.GONE);
if (mediaPlayer != null) {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
playState = PLAY_STATE_PLAYING;
handlerTimes.postDelayed(timeRunnable, 100);
actionBar.hide();
}
}
}
protected void playVideo() {
videoIcon.setVisibility(View.GONE);
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
} else {
if (isSurfaceCreated) {
mediaPlayer.setDisplay(surfaceHolder);
} else {
Toast.makeText(WatchVideoActivity.this, R.string.look_video_fail_try_again,
Toast.LENGTH_SHORT).show();
return;
}
}
mediaPlayer.reset();
try {
mediaPlayer.setDataSource(videoFilePath);
} catch (Exception e) {
Toast.makeText(WatchVideoActivity.this, R.string.look_video_fail_try_again,
Toast.LENGTH_SHORT).show();
e.printStackTrace();
return;
}
setMediaPlayerListener();
mediaPlayer.prepareAsync();
actionBar.hide();
}
}
private void setMediaPlayerListener() {
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
videoIcon.setVisibility(View.VISIBLE);
playState = PLAY_STATE_STOP;
playTimeTextView.setText("00:00");
handlerTimes.removeCallbacks(timeRunnable);
actionBar.show();
}
});
mediaPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
String type = "video/3gp";
Uri name = Uri.parse("file://" + videoFilePath);
intent.setDataAndType(name, type);
startActivity(intent);
finish();
} catch (Exception e) {
Toast.makeText(WatchVideoActivity.this, R.string.look_video_fail,
Toast.LENGTH_SHORT).show();
}
return true;
}
});
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp)// 缓冲完毕
{
mediaPlayer.start();// 播放视频
initVideoSize();//根据视频宽高,调整视频显示
// if (position > 0) {
// mediaPlayer.seekTo(position);
// mediaPlayer.start();
// }
handlerTimes.postDelayed(timeRunnable, 100);
}
});
}
/**
* **************************** 下载视频 *********************************
*/
private void showVideoInfo() {
long duration = ((VideoAttachment) message.getAttachment()).getDuration();
long fileSize = ((VideoAttachment) message.getAttachment()).getSize();
if (duration <= 0) {
fileInfoTextView.setText("大小: " + FileUtil.formatFileSize(fileSize));
} else {
long seconds = TimeUtil.getSecondsByMilliseconds(duration);
fileInfoTextView.setText("大小: " + FileUtil.formatFileSize(fileSize) + ",时长: "
+ String.valueOf(seconds) + " 秒");
videoLength = seconds;
}
}
private void registerObservers(boolean register) {
NIMClient.getService(MsgServiceObserve.class).observeMsgStatus(statusObserver, register);
NIMClient.getService(MsgServiceObserve.class).observeAttachmentProgress(attachmentProgressObserver, register);
}
private Observer<IMMessage> statusObserver = new Observer<IMMessage>() {
@Override
public void onEvent(IMMessage msg) {
if (!msg.isTheSame(message) || isDestroyedCompatible()) {
return;
}
if (msg.getAttachStatus() == AttachStatusEnum.transferred && isVideoHasDownloaded(msg)) {
onDownloadSuccess(msg);
} else if (msg.getAttachStatus() == AttachStatusEnum.fail) {
onDownloadFailed();
}
}
};
private Observer<AttachmentProgress> attachmentProgressObserver = new Observer<AttachmentProgress>() {
@Override
public void onEvent(AttachmentProgress p) {
long total = p.getTotal();
long progress = p.getTransferred();
float percent = (float) progress / (float) total;
if (percent > 1.0) {
// 消息中标识的文件大小有误,小于实际大小
percent = (float) 1.0;
progress = total;
}
if (percent - lastPercent >= 0.10) {
lastPercent = percent;
setDownloadProgress(getString(R.string.download_video), progress, total);
} else {
if (lastPercent == 0.0) {
lastPercent = percent;
setDownloadProgress(getString(R.string.download_video), progress, total);
}
if (percent == 1.0 && lastPercent != 1.0) {
lastPercent = percent;
setDownloadProgress(getString(R.string.download_video), progress, total);
}
}
}
};
private void setDownloadProgress(final String label, final long progress, final long total) {
final float percent = (float) ((double) progress / total);
runOnUiThread(new Runnable() {
@Override
public void run() {
LayoutParams fgLayoutParams = downloadProgressForeground.getLayoutParams();
fgLayoutParams.width = (int) (downloadProgressBackground.getWidth() * percent);
downloadProgressForeground.setLayoutParams(fgLayoutParams);
downloadProgressText.setText(String.format(getString(R.string.download_progress_description), label,
FileUtil.formatFileSize(progress), FileUtil.formatFileSize(total)));
}
});
}
private boolean isVideoHasDownloaded(final IMMessage message) {
if (message.getAttachStatus() == AttachStatusEnum.transferred &&
!TextUtils.isEmpty(((VideoAttachment) message.getAttachment()).getPath())) {
return true;
}
return false;
}
private void download() {
if (!isVideoHasDownloaded(message)) {
// async download original image
onDownloadStart(message);
downloadFuture = NIMClient.getService(MsgService.class).downloadAttachment(message, false);
downloading = true;
}
}
private void play() {
if (isVideoHasDownloaded(message)) {
onDownloadSuccess(message);
}
}
private void onDownloadSuccess(final IMMessage message) {
downloadFuture = null;
downloadLayout.setVisibility(View.GONE);
videoFilePath = ((VideoAttachment) message.getAttachment()).getPath();
surfaceView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (playState == PLAY_STATE_PAUSE) {
resumeVideo();
} else if (playState == PLAY_STATE_PLAYING) {
pauseVideo();
} else if (playState == PLAY_STATE_STOP) {
playVideo();
}
}
});
playVideo();
}
private void onDownloadFailed() {
downloadFuture = null;
downloadLayout.setVisibility(View.GONE);
Toast.makeText(WatchVideoActivity.this, R.string.download_video_fail, Toast.LENGTH_SHORT).show();
}
private void onDownloadStart(IMMessage message) {
setDownloadProgress(getString(R.string.download_video), 0, ((VideoAttachment) message.getAttachment()).getSize());
downloadLayout.setVisibility(View.VISIBLE);
}
private void stopDownload() {
if (downloadFuture != null) {
downloadFuture.abort();
downloadFuture = null;
downloading = false;
}
}
/**
* ***************************** SurfaceHolder Callback **************************************
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!isSurfaceCreated) {
isSurfaceCreated = true;
play();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isSurfaceCreated = false;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
initVideoSize();// 屏幕旋转后,改变视频显示布局
}
}