package io.github.mayubao.kuaichuan.ui;
import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.github.mayubao.kuaichuan.AppContext;
import io.github.mayubao.kuaichuan.Constant;
import io.github.mayubao.kuaichuan.R;
import io.github.mayubao.kuaichuan.common.BaseActivity;
import io.github.mayubao.kuaichuan.core.BaseTransfer;
import io.github.mayubao.kuaichuan.core.FileReceiver;
import io.github.mayubao.kuaichuan.core.entity.FileInfo;
import io.github.mayubao.kuaichuan.core.entity.IpPortInfo;
import io.github.mayubao.kuaichuan.core.utils.ApMgr;
import io.github.mayubao.kuaichuan.core.utils.FileUtils;
import io.github.mayubao.kuaichuan.core.utils.ToastUtils;
import io.github.mayubao.kuaichuan.ui.adapter.FileReceiverAdapter;
/**
* 文件接收列表界面
*
* ReceiverWaitingActivity --->>> 文件接收列表界面
*
* 前提条件:
* 1.文件发送方连接上文件接收方的局域网络(即为文件接收方的热点) 【TODO: 如何 文件接收方 收到 文件发送方的连接信息? UDP?】
* 如果是在文件发送UDP的话,那么应该在ReceiverWaitingActivity里面去监听
* 2.
*
* Created by mayubao on 2016/11/28.
* Contact me 345269374@qq.com
*/
public class FileReceiverActivity extends BaseActivity {
private static final String TAG = FileReceiverActivity.class.getSimpleName();
/**
* Topbar相关UI
*/
@Bind(R.id.tv_back)
TextView tv_back;
@Bind(R.id.tv_title)
TextView tv_title;
/**
* 进度条 已传 耗时等UI组件
*/
@Bind(R.id.pb_total)
ProgressBar pb_total;
@Bind(R.id.tv_value_storage)
TextView tv_value_storage;
@Bind(R.id.tv_unit_storage)
TextView tv_unit_storage;
@Bind(R.id.tv_value_time)
TextView tv_value_time;
@Bind(R.id.tv_unit_time)
TextView tv_unit_time;
/**
* 扫描结果
*/
@Bind(R.id.lv_result)
ListView lv_result;
FileReceiverAdapter mFileReceiverAdapter;
FileInfo mCurFileInfo;
IpPortInfo mIpPortInfo;
ServerRunnable mReceiverServer;
long mTotalLen = 0; //所有总文件的进度
long mCurOffset = 0; //每次传送的偏移量
long mLastUpdateLen = 0; //每个文件传送onProgress() 之前的进度
String[] mStorageArray = null;
long mTotalTime = 0;
long mCurTimeOffset = 0;
long mLastUpdateTime = 0;
String[] mTimeArray = null;
int mHasSendedFileCount = 0;
public static final int MSG_FILE_RECEIVER_INIT_SUCCESS = 0X4444;
public static final int MSG_ADD_FILE_INFO = 0X5555;
public static final int MSG_UPDATE_FILE_INFO = 0X6666;
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == MSG_FILE_RECEIVER_INIT_SUCCESS){
sendMsgToFileSender(mIpPortInfo);
}else if(msg.what == MSG_ADD_FILE_INFO){
//ADD FileInfo 到 Adapter
FileInfo fileInfo = (FileInfo) msg.obj;
ToastUtils.show(getContext(), "收到一个任务:" + (fileInfo != null ? fileInfo.getFilePath() : ""));
}else if(msg.what == MSG_UPDATE_FILE_INFO){
//ADD FileInfo 到 Adapter
updateTotalProgressView();
if(mFileReceiverAdapter != null) mFileReceiverAdapter.update();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_receiver);
ButterKnife.bind(this);
init();
}
@Override
public void onBackPressed() {
super.onBackPressed();
//关闭TCP UDP 资源
//清除选中文件的信息
//关闭热点
if(mReceiverServer != null){
mReceiverServer.close();
mReceiverServer = null;
}
closeSocket();
AppContext.getAppContext().getReceiverFileInfoMap().clear();
ApMgr.disableAp(getContext());
this.finish();
}
/**
* 初始化
*/
private void init(){
//界面初始化
tv_title.setVisibility(View.VISIBLE);
tv_title.setText(getResources().getString(R.string.title_file_transfer));
mFileReceiverAdapter = new FileReceiverAdapter(getContext());
lv_result.setAdapter(mFileReceiverAdapter);
mIpPortInfo = (IpPortInfo) getIntent().getSerializableExtra(Constant.KEY_IP_PORT_INFO);
//Android6.0 requires android.permission.READ_EXTERNAL_STORAGE
//TODO
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_WRITE_FILE);
}else{
initServer(); //启动接收服务
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_CODE_WRITE_FILE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initServer(); //启动接收服务
} else {
// Permission Denied
ToastUtils.show(this, getResources().getString(R.string.tip_permission_denied_and_not_receive_file));
onBackPressed();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
* 开启文件接收端服务
*/
private void initServer() {
mReceiverServer = new ServerRunnable(Constant.DEFAULT_SERVER_PORT);
new Thread(mReceiverServer).start();
}
/**
* 更新进度 和 耗时的 View
*/
private void updateTotalProgressView() {
try{
//设置传送的总容量大小
mStorageArray = FileUtils.getFileSizeArrayStr(mTotalLen);
tv_value_storage.setText(mStorageArray[0]);
tv_unit_storage.setText(mStorageArray[1]);
//设置传送的时间情况
mTimeArray = FileUtils.getTimeByArrayStr(mTotalTime);
tv_value_time.setText(mTimeArray[0]);
tv_unit_time.setText(mTimeArray[1]);
//设置传送的进度条情况
if(mHasSendedFileCount == AppContext.getAppContext().getReceiverFileInfoMap().size()){
pb_total.setProgress(0);
tv_value_storage.setTextColor(getResources().getColor(R.color.color_yellow));
tv_value_time.setTextColor(getResources().getColor(R.color.color_yellow));
return;
}
long total = AppContext.getAppContext().getAllReceiverFileInfoSize();
int percent = (int)(mTotalLen * 100 / total);
pb_total.setProgress(percent);
if(total == mTotalLen){
pb_total.setProgress(0);
tv_value_storage.setTextColor(getResources().getColor(R.color.color_yellow));
tv_value_time.setTextColor(getResources().getColor(R.color.color_yellow));
}
}catch (Exception e){
//convert storage array has some problem
}
}
@OnClick({R.id.tv_back})
public void onClick(View view){
switch (view.getId()){
case R.id.tv_back:{
onBackPressed();
break;
}
}
}
public void sendMsgToFileSender(final IpPortInfo ipPortInfo){
new Thread(){
@Override
public void run() {
try {
sendFileReceiverInitSuccessMsgToFileSender(ipPortInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
/**
* 通知文件发送方 ===>>> 文件接收方初始化完毕
*/
DatagramSocket mDatagramSocket;
public void sendFileReceiverInitSuccessMsgToFileSender(IpPortInfo ipPortInfo) throws Exception{
Log.i(TAG, "sendFileReceiverInitSuccessMsgToFileSender------>>>start");
mDatagramSocket = new DatagramSocket(ipPortInfo.getPort() +1);
byte[] receiveData = new byte[1024];
byte[] sendData = null;
InetAddress ipAddress = ipPortInfo.getInetAddress();
//1.发送 文件接收方 初始化
sendData = Constant.MSG_FILE_RECEIVER_INIT_SUCCESS.getBytes(BaseTransfer.UTF_8);
DatagramPacket sendPacket =
new DatagramPacket(sendData, sendData.length, ipAddress, ipPortInfo.getPort());
mDatagramSocket.send(sendPacket);
Log.i(TAG, "Send Msg To FileSender######>>>" + Constant.MSG_FILE_RECEIVER_INIT_SUCCESS);
Log.i(TAG, "sendFileReceiverInitSuccessMsgToFileSender------>>>end");
}
/**
* 关闭UDP Socket 流
*/
private void closeSocket(){
if(mDatagramSocket != null){
mDatagramSocket.disconnect();
mDatagramSocket.close();
mDatagramSocket = null;
}
}
/**
* ServerSocket启动线程
*/
class ServerRunnable implements Runnable{
ServerSocket serverSocket;
private int port;
public ServerRunnable(int port) {
this.port = port;
}
@Override
public void run() {
Log.i(TAG, "------>>>Socket已经开启");
try {
serverSocket = new ServerSocket(Constant.DEFAULT_SERVER_PORT);
mHandler.obtainMessage(MSG_FILE_RECEIVER_INIT_SUCCESS).sendToTarget();
while (!Thread.currentThread().isInterrupted()){
Socket socket = serverSocket.accept();
//生成缩略图
FileReceiver fileReceiver = new FileReceiver(socket);
fileReceiver.setOnReceiveListener(new FileReceiver.OnReceiveListener() {
@Override
public void onStart() {
// handler.obtainMessage(MSG_SHOW_PROGRESS).sendToTarget();
mLastUpdateLen = 0;
mLastUpdateTime = System.currentTimeMillis();
}
@Override
public void onGetFileInfo(FileInfo fileInfo) {
mHandler.obtainMessage(MSG_ADD_FILE_INFO, fileInfo).sendToTarget();
mCurFileInfo = fileInfo;
AppContext.getAppContext().addReceiverFileInfo(mCurFileInfo);
mHandler.sendEmptyMessage(MSG_UPDATE_FILE_INFO);
}
@Override
public void onGetScreenshot(Bitmap bitmap) {
// handler.obtainMessage(MSG_SHOW_PROGRESS, bitmap).sendToTarget();
}
@Override
public void onProgress(long progress, long total) {
//=====更新进度 流量 时间视图 start ====//
mCurOffset = progress - mLastUpdateLen > 0 ? progress - mLastUpdateLen : 0;
mTotalLen = mTotalLen + mCurOffset;
mLastUpdateLen = progress;
mCurTimeOffset = System.currentTimeMillis() - mLastUpdateTime > 0 ? System.currentTimeMillis() - mLastUpdateTime : 0;
mTotalTime = mTotalTime + mCurTimeOffset;
mLastUpdateTime = System.currentTimeMillis();
//=====更新进度 流量 时间视图 end ====//
mCurFileInfo.setProcceed(progress);
AppContext.getAppContext().updateReceiverFileInfo(mCurFileInfo);
mHandler.sendEmptyMessage(MSG_UPDATE_FILE_INFO);
}
@Override
public void onSuccess(FileInfo fileInfo) {
//=====更新进度 流量 时间视图 start ====//
mHasSendedFileCount ++;
mTotalLen = mTotalLen + (fileInfo.getSize() - mLastUpdateLen);
mLastUpdateLen = 0;
mLastUpdateTime = System.currentTimeMillis();
//=====更新进度 流量 时间视图 end ====//
fileInfo.setResult(FileInfo.FLAG_SUCCESS);
AppContext.getAppContext().updateReceiverFileInfo(fileInfo);
mHandler.sendEmptyMessage(MSG_UPDATE_FILE_INFO);
}
@Override
public void onFailure(Throwable t, FileInfo fileInfo) {
mHasSendedFileCount ++;//统计发送文件
fileInfo.setResult(FileInfo.FLAG_FAILURE);
AppContext.getAppContext().updateFileInfo(fileInfo);
mHandler.sendEmptyMessage(MSG_UPDATE_FILE_INFO);
}
});
// mFileReceiver = fileReceiver;
// new Thread(fileReceiver).start();
AppContext.getAppContext().MAIN_EXECUTOR.execute(fileReceiver);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 关闭Socket 通信 (避免端口占用)
*/
public void close(){
if(serverSocket != null){
try {
serverSocket.close();
serverSocket = null;
} catch (IOException e) {
}
}
}
}
}