最佳实践-p2p android聊天app源码
github源码下载地址 点击下载
本例子用于举例说明,利用kkp2p sdk来开发一个聊天app,该聊天app支持文字聊天以及传输图片文件。需要注意的是,本例子仅仅是一个demo,主要是说明kkp2p sdk在app中的基本用法,有些细节考虑不完善,请大家自行修改。该例子有少量代码拷贝于网上,感谢这些乐于分享的朋友。
使用局域网搜索模式无须部署云端服务。
一、app界面说明
主界面图片如下所示:
如上所示,界面上有云端的登录域名和端口号默认值,局域网搜索端口默认值
connect mode表示建连模式,缺省值是p2p模式,点击button有其他一些模式选择
account|sercret是登录账号和密码默认值。
如果使用局域网搜索模式,则无须部署云端服务,云端的登录域名和端口信息会被忽略掉。
点击login后就进入聊天界面,具体如下所示:
如上图所示,首先需要点击connect和目标端建连,建连成功后界面会弹出提示
点击最下面的file,可以从相册选择图片发送到目标端。
可以从输入框输入文件,然后点击send将文字发送到目标端。
二、代码简要说明
首先看MainActivity.java源码
package com.example.kkp2pjni;
import com.google.gson.Gson;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.example.kkp2pjni.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
// Used to load the 'kkp2pjni' library on application startup.
static {
// 需要用jni将libkkp2p.so中接口在封装一层给java调用,可以参考工程文件中的例子
System.loadLibrary("kkp2pjni");
}
private ActivityMainBinding binding;
private KKP2PEngine p2pEngine;
private long p2pHandle;
KKP2PConnectCtx connect_ctx;
KKP2PChannel channel;
private String src_peer_id;
private String src_peer_key;
private EditText login_domain;
private EditText login_port;
private EditText lan_port;
private Spinner connect_mode;
private Spinner account_info;
Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
intent = null;
// assign widget
login_domain = (EditText)findViewById(R.id.editDomain);
login_port = (EditText)findViewById(R.id.editPort);
lan_port = (EditText)findViewById(R.id.editLanPort);
// set select connect_mode
connect_mode = (Spinner) findViewById(R.id.spinnerMode);
String strConnMode="auto|0,p2p|1,relay|2,lanSearch";
String[] arrConnMode = strConnMode.split(",");
ArrayAdapter<String> adapterMode;
adapterMode = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, arrConnMode);
adapterMode.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
connect_mode.setAdapter(adapterMode);
connect_mode.setSelection(1);
connect_mode.setVisibility(View.VISIBLE);
// set select account_info
account_info = (Spinner) findViewById(R.id.spinnerAccount);
String strAccount="kkuai-ipc-00001|WtXmjG,kkuai-ipc-00002|OBq26M";
String[] arrAccount = strAccount.split(",");
ArrayAdapter<String> adapterAccount;
adapterAccount = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, arrAccount);
adapterAccount.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
account_info.setAdapter(adapterAccount);
account_info.setVisibility(View.VISIBLE);
p2pEngine = new KKP2PEngine();
p2pHandle = 0 ;
Button bt = findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// 初始化kkp2p sdk
KKP2PConfig config = new KKP2PConfig();
config.login_domain = login_domain.getText().toString();
config.login_port = Integer.parseInt(login_port.getText().toString());
config.lan_search_port = Integer.parseInt(lan_port.getText().toString());
config.log_path = null;
config.max_log_size = 1024*1024;
if (p2pHandle != 0) {
p2pEngine.nv_kkp2p_engine_destroy(p2pHandle);
}
p2pHandle = p2pEngine.nv_kkp2p_engine_init(config, 5000);
if (p2pHandle == 0) {
Toast toast = Toast.makeText(MainActivity.this, "p2p engine init error",
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
return;
}
// get connect param ctx
Boolean lanSearch = new Boolean("false");
connect_ctx = new KKP2PConnectCtx();
connect_ctx.connect_mode = 0;
// get connect mode
String strConnect = connect_mode.getSelectedItem().toString();
String[] strConnArray = strConnect.split("\\|");
if (strConnArray.length == 2) {
connect_ctx.connect_mode = Integer.parseInt(strConnArray[1]);
} else if (strConnArray[0].equals("lanSearch")) {
connect_ctx.connect_mode = 1;
lanSearch = true;
}
// get src peer id and dest peerId
String strAccount = account_info.getSelectedItem().toString();
String[] strAccountArray = strAccount.split("\\|");
src_peer_id = strAccountArray[0];
src_peer_key = strAccountArray[1];
// 缺省的登录账号
if (src_peer_id.equals("kkuai-ipc-00001")) {
connect_ctx.peer_id = "kkuai-ipc-00002";
} else {
connect_ctx.peer_id = "kkuai-ipc-00001";
}
connect_ctx.encrypt_data = 0;
connect_ctx.time_out = 5000;
connect_ctx.func = null;
connect_ctx.func_param = null;
// 加入到云端网络
int result = p2pEngine.nv_kkp2p_join_net(p2pHandle, src_peer_id, src_peer_key);
if (result < 0) {
Toast.makeText(MainActivity.this, "kkp2p join net error",
Toast.LENGTH_SHORT).show();
return;
}
// 加入到局域网络
result = p2pEngine.nv_kkp2p_join_lan(p2pHandle, src_peer_id);
if (result < 0) {
Toast.makeText(MainActivity.this, "kkp2p join lan error",
Toast.LENGTH_SHORT).show();
return;
}
// start the chat activity
if (intent == null) {
intent = new Intent(MainActivity.this, ChatActivity.class);
}
// put data to chat activity
Gson gs = new Gson();
String targetCtx = gs.toJson(connect_ctx);
intent.putExtra("extraConnectCtx", targetCtx);
intent.putExtra("extraP2PHandle", p2pHandle);
intent.putExtra("lanSearch", lanSearch);
startActivity(intent);
}
});
}
}
再看ChatActivity.java源码
package com.example.kkp2pjni;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
public class ChatActivity<Unit> extends AppCompatActivity {
private KKP2PEngine p2pEngine;
// clientChannel can read and wirte data
private KKP2PChannel clientChannel;
// acceptChannel can read and write data too
private ArrayList<KKP2PChannel> acceptChannelArray;
private long p2pHandle;
private int listenFd;
private Button picButton;
private Button sendButton;
private TextView msgText;
private RecyclerView recyclerView;
private ArrayList<Msg> msgList;
private MsgAdapter msgAdapter;
private ProgressBar progressBar;
private KKP2PConnectCtx connect_ctx;
private boolean lanSearch;
private Thread accept_thread;
private boolean accept_exit;
private Thread recv_thread;
private SocketHandler mHandler;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
// init view
msgText = (EditText)findViewById(R.id.input_text);
sendButton = (Button)findViewById(R.id.send);
picButton = (Button)findViewById(R.id.pic);
// init recycler
recyclerView = (RecyclerView) findViewById(R.id.msg_recycler_view);
msgList = new ArrayList<Msg>();
msgAdapter = new MsgAdapter(msgList);
recyclerView.setAdapter(msgAdapter);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager);
// init progressBar
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setVisibility(View.GONE);
mHandler = new SocketHandler();
// init p2p engine
p2pEngine = new KKP2PEngine();
connect_ctx = new KKP2PConnectCtx();
clientChannel = new KKP2PChannel();
acceptChannelArray = new ArrayList<KKP2PChannel>();
Intent intent = getIntent();
String strCtx = intent.getStringExtra("extraConnectCtx");
Gson gs = new Gson();
connect_ctx = gs.fromJson(strCtx, KKP2PConnectCtx.class);
p2pHandle = intent.getLongExtra("extraP2PHandle",0);
listenFd = p2pEngine.nv_kkp2p_listen_fd(p2pHandle);
lanSearch = intent.getBooleanExtra("lanSearch",false);
Log.d("KKP2P","lanSearch:" + lanSearch);
// set friend account
Button firendBT = (Button) findViewById(R.id.friend);
firendBT.setText(connect_ctx.peer_id);
// set connect listen
Button btConnect = findViewById(R.id.connect);
btConnect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// 主动创建连接
int result = -1;
if (lanSearch) {
result = p2pEngine.nv_kkp2p_lan_search(p2pHandle, connect_ctx, clientChannel);
} else {
result = p2pEngine.nv_kkp2p_connect(p2pHandle, connect_ctx, clientChannel);
}
if (result < 0) {
Toast toast = Toast.makeText(ChatActivity.this, "kkp2p connect error",
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
return;
} else {
Toast toast = Toast.makeText(ChatActivity.this, "kkp2p connect success",
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
}
Button connetBT = (Button) findViewById(R.id.connect);
if (clientChannel.transmit_mode == 1) {
connetBT.setText("p2p");
} else {
connetBT.setText("relay");
}
connetBT.setEnabled(false);
// begin recv data from channel
StartRecvThread();
}
});
sendButton.setOnClickListener(new View.OnClickListener() {
@SuppressLint("StaticFieldLeak")
public void onClick(View v) {
new AsyncTask<String, Integer, String>() {
protected String doInBackground(String... params) {
int result = 0;
if (getAcceptChannel() != null && getAcceptChannel().fd > 0) {
result = sendMsg(getAcceptChannel());
if (result <0) {
KKP2PEngine.nv_kkp2p_close_fd(getAcceptChannel().fd);
KKP2PEngine.nv_kkp2p_close_channel(p2pHandle, getAcceptChannel().channel_id);
getAcceptChannel().fd = -1;
getAcceptChannel().channel_id = 0;
}
} else if (clientChannel.fd > 0) {
result = sendMsg(clientChannel);
if (result < 0 ) {
KKP2PEngine.nv_kkp2p_close_fd(clientChannel.fd);
KKP2PEngine.nv_kkp2p_close_channel(p2pHandle,clientChannel.channel_id);
clientChannel.fd = -1;
clientChannel.channel_id = 0;
}
} else {
return null;
}
if (result < 0 ) {
Message msg = mHandler.obtainMessage();
String strDesc = "kkp2p_write error, close fd and channel";
msg.what = 4;
msg.obj = strDesc;
msg.sendToTarget();
}
return null;
}
}.execute();
}
});
// on pic button
int REQUEST_CODE_CONTACT = 101;
String[] permissions = {Manifest.permission.READ_EXTERNAL_STORAGE};
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
}
}
ActivityResultLauncher activityResultLauncher = registerForActivityResult(
new ResultContract(),
result -> {
Toast toast = Toast.makeText(ChatActivity.this, result,
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
String imagePath = result;
new AsyncTask<String, Integer, String>() {
protected String doInBackground(String... params) {
sendMediaFile(params[0]);
return null;
}
}.execute(imagePath);
});
picButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("video/*;image/*");
activityResultLauncher.launch(intent);
}
});
// 启动单独线程接收远程连接
accept_exit = false;
StartAcceptThread();
}
// 如果有多个连接,则获取一个最新的连接
private KKP2PChannel getAcceptChannel() {
int count = acceptChannelArray.size();
if (count > 0) {
return acceptChannelArray.get(count - 1);
}
return null;
}
protected int sendSocketMsg(KKP2PChannel channel, byte[] byteArray, int expectLen) {
int snd = 0 ;
int sended = 0;
snd = p2pEngine.nv_kkp2p_write(channel.fd, byteArray, expectLen,5000);
if (snd < 0 ) {
return -1;
}
sended += snd;
while ( sended < expectLen) {
byte[] tmpArray = new byte[expectLen - sended];
System.arraycopy(byteArray,sended,tmpArray,0,expectLen - sended);
snd = p2pEngine.nv_kkp2p_write(channel.fd, tmpArray, tmpArray.length,5000);
if (snd < 0 ) {
return -1;
}
sended += snd;
}
return sended;
}
protected int recvSocketMsg(KKP2PChannel channel,byte[] byteArray, int expectLen) {
int recv = 0 ;
int recved = 0;
recv = p2pEngine.nv_kkp2p_read(channel.fd, byteArray, expectLen,5000);
if (recv < 0 ) {
Log.e("KKP2P","nv_kkp2p_read error,error code:" + recv);
return -1;
}
recved += recv;
while (recved < expectLen) {
byte[] tmpArray = new byte[expectLen - recved];
recv = p2pEngine.nv_kkp2p_read(channel.fd, tmpArray, tmpArray.length,5000);
if (recv < 0 ) {
Log.e("KKP2P","nv_kkp2p_read error,error code:" + recv);
return -1;
}
System.arraycopy(tmpArray,0,byteArray,recved,recv);
recved += recv;
}
return recved;
}
// 发送文本消息
protected int sendMsg(KKP2PChannel channel) {
int result = 0;
try {
String text = msgText.getText().toString().trim();
// 协议格式为TLV
// T表示tag,1是文本消息,2是文件消息
// L表示长度
// V表示内容
byte[] tagArray = ByteConvert.uintToBytes(1);
result = sendSocketMsg(channel,tagArray,tagArray.length);
if (result < 0) {
return result;
}
// send length
byte[] byteArray = text.getBytes();
byte[] lengthArray = ByteConvert.uintToBytes(byteArray.length);
result = sendSocketMsg(channel,lengthArray,lengthArray.length);
if (result < 0) {
return result;
}
// send value
result = sendSocketMsg(channel,byteArray,byteArray.length);
if (result < 0) {
return result;
}
Message message = new Message();
message.what = Msg.TYPE_SENT;
message.obj = text;
mHandler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
protected int sendMediaFile(String imagePath) {
int result = 0;
if (getAcceptChannel() != null && getAcceptChannel().fd > 0) {
result = sendFile(getAcceptChannel(),imagePath);
if (result < 0) {
KKP2PEngine.nv_kkp2p_close_fd(getAcceptChannel().fd);
KKP2PEngine.nv_kkp2p_close_channel(p2pHandle, getAcceptChannel().channel_id);
getAcceptChannel().fd = -1;
getAcceptChannel().channel_id = 0;
}
} else if (clientChannel.fd > 0) {
result = sendFile(clientChannel,imagePath);
if (result < 0 ) {
KKP2PEngine.nv_kkp2p_close_fd(clientChannel.fd);
KKP2PEngine.nv_kkp2p_close_channel(p2pHandle,clientChannel.channel_id);
clientChannel.fd = -1;
clientChannel.channel_id = 0;
}
}
if (result < 0 ) {
Message msg = mHandler.obtainMessage();
String strDesc = "kkp2p_write error, close fd and channel";
msg.what = 4;
msg.obj = strDesc;
msg.sendToTarget();
}
return result;
}
// 发送文件内容
protected int sendFile(KKP2PChannel channel,String imagePath) {
Log.d("KKP2P","begin send file:" + imagePath);
int result = 0;
try {
File file = new File(imagePath);
long fileLen = file.length();
// the protocol format is TLV:tag,lenth,value
// send file tag is 2
byte[] tagArray = ByteConvert.uintToBytes(2);
result = sendSocketMsg(channel,tagArray,tagArray.length);
if (result < 0) {
return result;
}
// send length
byte[] lengthArray = ByteConvert.uintToBytes(fileLen);
result = sendSocketMsg(channel,lengthArray,lengthArray.length);
if (result < 0) {
return result;
}
long startMs = System.currentTimeMillis();
byte[] buffer = new byte[1024];
int len = 0;
FileInputStream inStream = new FileInputStream(file);
int totalSended = 0 ;
while( (len = inStream.read(buffer))!= -1) {
result = sendSocketMsg(channel,buffer,len);
if (result < 0) {
return result;
}
totalSended += len;
// 更新发送文件的进度条
Message message = Message.obtain();
message.obj = (int)((long)totalSended * 100 /fileLen);
message.what = 5;
mHandler.sendMessage(message);
}
// send success
long endMs = System.currentTimeMillis();
Message message = Message.obtain();
String strDesc = "send file len:"+ fileLen
+ ",speed:" + fileLen*1000/(endMs-startMs) + " Byte/s";
message.obj = strDesc;
message.what = 6;
mHandler.sendMessage(message);
inStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
// 接收远端的数据,文本或者文件
private void LoopReadChannel(KKP2PChannel channel) {
// loop recv msg
int recvLen = 0;
while (true) {
recvLen = recvMsgAndFile(channel);
if (recvLen < 0) {
String strDesc = "kkp2p_read error, close fd and channel,fd:"
+ channel.fd + ",result:" + recvLen + ",channel hash code:"
+ channel.hashCode();
Log.e("KKP2P","LoopReadChannel:" + strDesc);
// socket error
p2pEngine.nv_kkp2p_close_channel(p2pHandle,channel.channel_id);
p2pEngine.nv_kkp2p_close_fd(channel.fd);
channel.fd = -1;
channel.channel_id = 0;
Message msg = mHandler.obtainMessage();
msg.what = 4;
msg.obj = strDesc;
msg.sendToTarget();
return;
}
}
}
protected int recvMsgAndFile(KKP2PChannel channel) {
// recv tag
byte[] tagArray = new byte[4];
int result = recvSocketMsg(channel,tagArray,tagArray.length);
if (result < 0 ) {
return result;
}
long tag = ByteConvert.bytesToUint(tagArray);
// recv length
byte []lenArray = new byte[4];
result = recvSocketMsg(channel,lenArray,lenArray.length);
if (result < 0 ) {
return result;
}
long length = ByteConvert.bytesToUint(lenArray);
if (tag == 1) {
// tag为1表示文本消息
byte[] textArray = new byte[(int)length];
result = recvSocketMsg(channel,textArray,textArray.length);
if (result < 0 ) {
return result;
}
Message msg = mHandler.obtainMessage();
String text = new String(textArray,0,result);
msg.what = Msg.TYPE_RECEIVED;
msg.obj = text;
msg.sendToTarget();
} else if (tag == 2) {
// tag为2表示文件
// 例子将接收到的文件丢弃处理,如有必要大家可以完善逻辑将文件保存起来
long startMs = System.currentTimeMillis();
int totalReceived = 0;
byte[] byteArray = new byte[1024];
while(totalReceived < length) {
int expectLen= Math.min(1024, (int)length-totalReceived);
result = recvSocketMsg(channel,byteArray, expectLen);
if (result < 0 ) {
return result;
}
totalReceived += result;
}
long endMs = System.currentTimeMillis();
Message msg = mHandler.obtainMessage();
String text = "recv file,len:" + totalReceived + ",speed:" +
(totalReceived/(endMs-startMs))*1000 + " Byte/s,discard it";
msg.what = Msg.TYPE_RECEIVED;
msg.obj = text;
msg.sendToTarget();
}
return (int)length;
}
private void StartRecvThread() {
// create accept thread to accept connect
recv_thread = new Thread(new Runnable() {
public void run() {
LoopReadChannel(clientChannel);
}
});
recv_thread.start();
}
// 接收远端的连接
private void StartAcceptThread() {
accept_thread = new Thread(new Runnable() {
public void run() {
while (true) {
int result = 0;
KKP2PChannel acceptChannel = new KKP2PChannel();
while (result == 0) {
// result为0表示超时
result = p2pEngine.nv_kkp2p_accept(p2pHandle,1000, acceptChannel);
if (result <0 || accept_exit) {
// error
Log.d("KKP2P","accept thread exit");
return ;
}
}
String strLog = "nv_kkp2p_accept a new channel success,"
+ "fd:" + acceptChannel.fd + ",transmit_mode:"
+ acceptChannel.transmit_mode + "," + ",p2pHandle"
+ p2pHandle;
Log.d("KKP2P", strLog);
String strDesc = new String("");
if (acceptChannel.transmit_mode == 1) {
strDesc = "p2p(accepted)";
} else if (acceptChannel.transmit_mode == 2) {
strDesc = "relay(accepted)";
}
Message msg = mHandler.obtainMessage();
msg.what = 3;
msg.obj = strDesc;
msg.sendToTarget();
Thread recvThread = new Thread(new Runnable() {
public void run() {
// second, loop read from this channel
LoopReadChannel(acceptChannel);
}
});
recvThread.start();
// add to list
acceptChannelArray.add(acceptChannel);
}
}
});
accept_thread.start();
}
// 集中处理内部的消息
class SocketHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LinearLayoutManager manager;
switch (msg.what) {
case 0:
// recv msg
try {
String text = new String((String)msg.obj);
Msg chatMsg = new Msg(text, 0);
msgList.add(chatMsg);
Log.d("KKP2P","recv msg:"+text +",p2pHandle:"+ p2pHandle);
} catch (Exception e) {
e.printStackTrace();
}
msgAdapter.notifyItemInserted(msgList.size()-1);
recyclerView.scrollToPosition(msgAdapter.getItemCount()-1);
break;
case 1:
// send msg
try {
String text = new String((String)msg.obj);
Msg chatMsg = new Msg(text, 1);
msgList.add(chatMsg);
} catch (Exception e) {
e.printStackTrace();
}
msgAdapter.notifyItemInserted(msgList.size()-1);
recyclerView.scrollToPosition(msgAdapter.getItemCount()-1);
msgText.setText("");
break;
case 3:
// update button
try {
String text = new String((String)msg.obj);
String strLog = "accept channel type desc:" + text;
Button connetBT = (Button) findViewById(R.id.connect);
connetBT.setText(text);
connetBT.setEnabled(false);
String strToast = "accepted a new connection:" + text;
Toast toast = Toast.makeText(ChatActivity.this,
strToast, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
} catch (Exception e) {
e.printStackTrace();
}
break;
case 4:
// notify close channel
try {
String text = new String((String)msg.obj);
Toast toast = Toast.makeText(ChatActivity.this,
text, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
Button connetBT = (Button) findViewById(R.id.connect);
connetBT.setText("disconnect");
} catch (Exception e) {
e.printStackTrace();
}
break;
case 5:
// update progress
try {
int percent = (int)msg.obj;
if (percent >0 && percent < 100) {
progressBar.setVisibility(View.VISIBLE);
progressBar.setProgress(percent);
} else {
progressBar.setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
case 6:
// update progress
try {
String text = new String((String)msg.obj);
Msg chatMsg = new Msg(text, 1);
msgList.add(chatMsg);
} catch (Exception e) {
e.printStackTrace();
}
msgAdapter.notifyItemInserted(msgList.size()-1);
recyclerView.scrollToPosition(msgAdapter.getItemCount()-1);
break;
default:
break;
}
}
}
public class ResultContract extends ActivityResultContract<Intent, String> {
Context myContext;
public Intent createIntent(Context context, Intent input) {
myContext = context;
return new Intent(Intent.ACTION_GET_CONTENT).setType("video/*;image/*");
}
public String parseResult(int resultCode, Intent data) {
Uri uri = data.getData();
return PickUtils.getPath(myContext, uri);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
accept_exit = true;
Log.d("KKP2P","activity onDestroy");
}
public static String bytes2hex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
String tmp;
sb.append("[");
int i = 0;
for (byte b : bytes) {
tmp = Integer.toHexString(0xFF & b);
if (tmp.length() == 1) {
tmp = "0" + tmp;
}
sb.append(tmp).append(" ");
}
sb.delete(sb.length() - 1, sb.length());
sb.append("]");
return sb.toString();
}
}