diff --git a/app/build.gradle b/app/build.gradle index c4d464c..641afcd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,6 +55,7 @@ dependencies { implementation rootProject.ext.dependencies.rxandroid // 从车机获取视频流 implementation 'com.zhidao.carmanager:common:1.0.25@aar' + implementation 'com.google.android.material:material:1.3.0' if (Boolean.valueOf(RELEASE)) { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b9d61f..b298064 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,7 +13,6 @@ - @@ -21,14 +20,17 @@ + @@ -38,7 +40,6 @@ - - - + + \ No newline at end of file diff --git a/app/src/main/java/com/mogo/cloud/MainActivity.java b/app/src/main/java/com/mogo/cloud/MainActivity.java index 6a2915a..c19fea1 100644 --- a/app/src/main/java/com/mogo/cloud/MainActivity.java +++ b/app/src/main/java/com/mogo/cloud/MainActivity.java @@ -44,6 +44,7 @@ public class MainActivity extends AppCompatActivity { private Button btnV2XFunctionTest; private boolean v2xHasBeenInitialized = false; + private Button btnNSDNetty; private SurfaceView surfacePreviewView; private TextView tvSn; @@ -167,6 +168,7 @@ public class MainActivity extends AppCompatActivity { }); btnRequestCarLive = findViewById(R.id.btnRequestCarLive); + btnNSDNetty = findViewById(R.id.btnNSDNetty); surfacePreviewView = findViewById(R.id.surfacePreviewView); btnRequestCarLive.setOnClickListener(v -> { MoGoAiCloudTrafficLive.viewFrontVehicleLive(40.11547, 116.22544, @@ -203,6 +205,10 @@ public class MainActivity extends AppCompatActivity { } }); }); + btnNSDNetty.setOnClickListener(v -> { + Intent intent = new Intent(MainActivity.this, NSDNettyActivity.class); + startActivity(intent); + }); //V2X功能测试 btnV2XFunctionTest = findViewById(R.id.btnV2XFunctionTest); diff --git a/app/src/main/java/com/mogo/cloud/NSDNettyActivity.java b/app/src/main/java/com/mogo/cloud/NSDNettyActivity.java new file mode 100644 index 0000000..40714c4 --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/NSDNettyActivity.java @@ -0,0 +1,37 @@ +package com.mogo.cloud; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import com.mogo.cloud.netty.client.NettyClientActivity; +import com.mogo.cloud.netty.server.NettyServerActivity; + +public class NSDNettyActivity extends AppCompatActivity { + + private Button btnNettyServer; + private Button btnNettyClient; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_nsdnetty); + initView(); + } + + private void initView() { + btnNettyServer = findViewById(R.id.btnNettyServer); + btnNettyServer.setOnClickListener(v -> { + Intent intent = new Intent(NSDNettyActivity.this, NettyServerActivity.class); + startActivity(intent); + }); + btnNettyClient = findViewById(R.id.btnNettyClient); + btnNettyClient.setOnClickListener(v -> { + Intent intent = new Intent(NSDNettyActivity.this, NettyClientActivity.class); + startActivity(intent); + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/cloud/netty/LogBean.java b/app/src/main/java/com/mogo/cloud/netty/LogBean.java new file mode 100644 index 0000000..c3814f3 --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/netty/LogBean.java @@ -0,0 +1,14 @@ +package com.mogo.cloud.netty; + +import java.text.SimpleDateFormat; + +public class LogBean { + public String mTime; + public String mLog; + + public LogBean(long time, String log) { + SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss"); + mTime = format.format(time); + mLog = log; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/cloud/netty/client/LogAdapter.java b/app/src/main/java/com/mogo/cloud/netty/client/LogAdapter.java new file mode 100644 index 0000000..9e1fd9f --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/netty/client/LogAdapter.java @@ -0,0 +1,69 @@ +package com.mogo.cloud.netty.client; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.cloud.R; +import com.mogo.cloud.netty.LogBean; + +import java.util.ArrayList; +import java.util.List; + + +public class LogAdapter extends RecyclerView.Adapter { + + private List mDataList = new ArrayList<>(); + + @Override + public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.log_item, parent, false)); + } + + @Override + public void onBindViewHolder(final ItemHolder holder, int position) { + LogBean bean = mDataList.get(position); + + holder.mTime.setText(bean.mTime); + holder.mLog.setText(bean.mLog); + + holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + ClipboardManager cmb = (ClipboardManager) v.getContext().getSystemService(Context.CLIPBOARD_SERVICE); + LogBean log = mDataList.get(holder.getAdapterPosition()); + String msg = log.mTime + " " + log.mLog; + cmb.setPrimaryClip(ClipData.newPlainText(null, msg)); + Toast.makeText(v.getContext(), "已复制到剪贴板", Toast.LENGTH_LONG).show(); + return true; + } + }); + } + + @Override + public int getItemCount() { + return mDataList.size(); + } + + public class ItemHolder extends RecyclerView.ViewHolder { + public TextView mTime; + public TextView mLog; + + public ItemHolder(View itemView) { + super(itemView); + mTime = (TextView) itemView.findViewById(R.id.time); + mLog = (TextView) itemView.findViewById(R.id.logtext); + } + } + + public List getDataList() { + return mDataList; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/cloud/netty/client/NettyClientActivity.java b/app/src/main/java/com/mogo/cloud/netty/client/NettyClientActivity.java new file mode 100644 index 0000000..58271b3 --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/netty/client/NettyClientActivity.java @@ -0,0 +1,240 @@ +package com.mogo.cloud.netty.client; + +import android.net.nsd.NsdServiceInfo; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.cloud.R; +import com.mogo.cloud.netty.LogBean; +import com.mogo.telematic.client.NettyTcpClient; +import com.mogo.telematic.client.NsdClient; +import com.mogo.telematic.client.listener.MessageStateListener; +import com.mogo.telematic.client.listener.NettyClientListener; +import com.mogo.telematic.client.status.ConnectState; + +public class NettyClientActivity extends AppCompatActivity implements View.OnClickListener, NettyClientListener { + + private static final String TAG = "NettyClientActivity"; + // client端用来过滤的 + public static final String SERVER_NAME = "NSD_SERVER"; + + private Button mClearLog; + private Button mSendBtn; + private Button mConnect; + private EditText mSendET; + private RecyclerView mSendList; + private RecyclerView mReceList; + private EditText mInputIp; + + private LogAdapter mSendLogAdapter = new LogAdapter(); + private LogAdapter mReceLogAdapter = new LogAdapter(); + private NettyTcpClient mNettyTcpClient; + private NsdClient nsdClient; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_netty_client); + findViews(); + initView(); + searchNsdServer(); + } + + private void initView() { + LinearLayoutManager manager1 = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + mSendList.setLayoutManager(manager1); + mSendList.setAdapter(mSendLogAdapter); + + LinearLayoutManager manager2 = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + mReceList.setLayoutManager(manager2); + mReceList.setAdapter(mReceLogAdapter); + } + + private void findViews() { + mSendList = findViewById(R.id.send_list); + mReceList = findViewById(R.id.rece_list); + mSendET = findViewById(R.id.send_et); + mConnect = findViewById(R.id.connect); + mSendBtn = findViewById(R.id.send_btn); + mClearLog = findViewById(R.id.clear_log); + mInputIp = findViewById(R.id.et_ip); + + mConnect.setOnClickListener(this); + mSendBtn.setOnClickListener(this); + mClearLog.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.connect: +// connectNettyServer(mInputIp.getText().toString().trim(), Const.TCP_PORT); + break; + + case R.id.send_btn: + if (!mNettyTcpClient.getConnectStatus()) { + Toast.makeText(getApplicationContext(), "未连接,请先连接", Toast.LENGTH_SHORT).show(); + } else { + final String msg = mSendET.getText().toString(); + if (TextUtils.isEmpty(msg.trim())) { + return; + } + mNettyTcpClient.sendMsgToServer(msg, new MessageStateListener() { + @Override + public void isSendSuccss(boolean isSuccess) { + if (isSuccess) { + Log.d(TAG, "Write auth successful"); + logSend(msg); + } else { + Log.d(TAG, "Write auth error"); + } + } + }); + mSendET.setText(""); + } + + break; + + case R.id.clear_log: + mReceLogAdapter.getDataList().clear(); + mSendLogAdapter.getDataList().clear(); + mReceLogAdapter.notifyDataSetChanged(); + mSendLogAdapter.notifyDataSetChanged(); + break; + } + } + + /** + * 通过Nsd搜索注册过的服务端名称解析后拿到 IP 和端口,进行NettySocket的连接 + */ + private void searchNsdServer() { + + nsdClient = new NsdClient(NettyClientActivity.this, SERVER_NAME, new NsdClient.IServerFound() { + @Override + public void onServerFound(NsdServiceInfo info, int port) { + if (info != null) { + String hostAddress = info.getHost().getHostAddress(); + Log.d(TAG, "NSD查询到指定服务器信息ip为:" + hostAddress + ",port为:" + port); + //获取到指定的地址,进行Netty的连接 + connectNettyServer(hostAddress, port); + + if (info.getServiceName().equals(SERVER_NAME)) { + //扫描到以后停止 + nsdClient.stopNSDServer(); + } + } + } + + @Override + public void onServerFail() { + + } + }); + + nsdClient.startNSDClient(); + } + + private void connectNettyServer(String serverAddress, int port) { + Log.d(TAG, "connectNettyServer"); + if (serverAddress == null || serverAddress.length() == 0) { + Toast.makeText(this, "ip不能为空!", Toast.LENGTH_SHORT).show(); + return; + } + if (mNettyTcpClient == null) { + mNettyTcpClient = new NettyTcpClient.Builder() + .setHost(serverAddress) //设置服务端地址 + .setTcpPort(port) //设置服务端端口号 + .setMaxReconnectTimes(5) //设置最大重连次数 + .setReconnectIntervalTime(5) //设置重连间隔时间。单位:秒 + .setSendheartBeat(true) //设置是否发送心跳 + .setHeartBeatInterval(5) //设置心跳间隔时间。单位:秒 + .setHeartBeatData("I'm is HeartBeatData") //设置心跳数据,可以是String类型,也可以是byte[],以后设置的为准 + .setIndex(0) //设置客户端标识.(因为可能存在多个tcp连接) +// .setPacketSeparator("#")//用特殊字符,作为分隔符,解决粘包问题,默认是用换行符作为分隔符 +// .setMaxPacketLong(1024)//设置一次发送数据的最大长度,默认是1024,最大值为Integer.MAX + .build(); + mNettyTcpClient.setListener(NettyClientActivity.this); //设置TCP监听 + } + + if (!mNettyTcpClient.getConnectStatus()) { + mNettyTcpClient.connect();//连接服务器 + } else { + mNettyTcpClient.disconnect(); + } + } + + @Override + public void onMessageResponseClient(String msg, int index) { + Log.e(TAG, "onMessageResponse:" + msg); + logRece(index + ":" + msg); + } + + @Override + public void onClientStatusConnectChanged(final int statusCode, final int index) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (statusCode == ConnectState.STATUS_CONNECT_SUCCESS) { + Log.e(TAG, "STATUS_CONNECT_SUCCESS:"); + mConnect.setText("DisConnect:" + index); + } else { + Log.e(TAG, "onServiceStatusConnectChanged:" + statusCode); + mConnect.setText("Connect:" + index); + } + } + }); + + } + + private void logSend(String log) { + LogBean logBean = new LogBean(System.currentTimeMillis(), log); + mSendLogAdapter.getDataList().add(0, logBean); + runOnUiThread(new Runnable() { + @Override + public void run() { + mSendLogAdapter.notifyDataSetChanged(); + } + }); + + } + + private void logRece(String log) { + LogBean logBean = new LogBean(System.currentTimeMillis(), log); + mReceLogAdapter.getDataList().add(0, logBean); + runOnUiThread(new Runnable() { + @Override + public void run() { + mReceLogAdapter.notifyDataSetChanged(); + } + }); + + } + + /** + * 方法三: + * byte[] to hex string + * + * @param bytes + * @return + */ + public static String bytesToHexFun3(byte[] bytes, int length) { + StringBuilder buf = new StringBuilder(length * 2); + for (int i = 0; i < length; i++) {// 使用String的format方法进行转换 + buf.append(String.format("%02x", new Integer(bytes[i] & 0xFF))); + } + return buf.toString(); + } + + public void disconnect(View view) { + mNettyTcpClient.disconnect(); + } +} diff --git a/app/src/main/java/com/mogo/cloud/netty/server/CustomSpinnerAdapter.java b/app/src/main/java/com/mogo/cloud/netty/server/CustomSpinnerAdapter.java new file mode 100644 index 0000000..980c1b7 --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/netty/server/CustomSpinnerAdapter.java @@ -0,0 +1,66 @@ +package com.mogo.cloud.netty.server; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.mogo.telematic.server.bean.ClientChanel; + +import java.util.List; + + +/** + * Created by IT小蔡 on 2018-11-10. + */ + +public class CustomSpinnerAdapter extends BaseAdapter { + + private int layoutId; + private Context mContext; + private List mData; + private final LayoutInflater mInflater; + + public CustomSpinnerAdapter(@NonNull Context context, List list) { + this.mContext = context; + this.mData = list; + mInflater = LayoutInflater.from(context); + } + + @Override + public int getCount() { + return mData.size(); + } + + @Override + public ClientChanel getItem(int position) { + return mData.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final View view; + final TextView text; + + if (convertView == null) { + view = mInflater.inflate(android.R.layout.simple_spinner_item, parent, false); + } else { + view = convertView; + } + + text = (TextView) view; + ClientChanel item = getItem(position); + text.setText(item.getClientIp()); + + return view; + } +} diff --git a/app/src/main/java/com/mogo/cloud/netty/server/LogAdapter.java b/app/src/main/java/com/mogo/cloud/netty/server/LogAdapter.java new file mode 100644 index 0000000..eec52db --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/netty/server/LogAdapter.java @@ -0,0 +1,69 @@ +package com.mogo.cloud.netty.server; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.cloud.R; +import com.mogo.cloud.netty.LogBean; + +import java.util.ArrayList; +import java.util.List; + + +public class LogAdapter extends RecyclerView.Adapter { + + private List mDataList = new ArrayList<>(); + + @Override + public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.log_item, parent, false)); + } + + @Override + public void onBindViewHolder(final ItemHolder holder, int position) { + LogBean bean = mDataList.get(position); + + holder.mTime.setText(bean.mTime); + holder.mLog.setText(bean.mLog); + + holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + ClipboardManager cmb = (ClipboardManager) v.getContext().getSystemService(Context.CLIPBOARD_SERVICE); + LogBean log = mDataList.get(holder.getAdapterPosition()); + String msg = log.mTime + " " + log.mLog; + cmb.setPrimaryClip(ClipData.newPlainText(null, msg)); + Toast.makeText(v.getContext(), "已复制到剪贴板", Toast.LENGTH_LONG).show(); + return true; + } + }); + } + + @Override + public int getItemCount() { + return mDataList.size(); + } + + public class ItemHolder extends RecyclerView.ViewHolder { + public TextView mTime; + public TextView mLog; + + public ItemHolder(View itemView) { + super(itemView); + mTime = (TextView) itemView.findViewById(R.id.time); + mLog = (TextView) itemView.findViewById(R.id.logtext); + } + } + + public List getDataList() { + return mDataList; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/cloud/netty/server/NettyServerActivity.java b/app/src/main/java/com/mogo/cloud/netty/server/NettyServerActivity.java new file mode 100644 index 0000000..c4ebc2e --- /dev/null +++ b/app/src/main/java/com/mogo/cloud/netty/server/NettyServerActivity.java @@ -0,0 +1,324 @@ +package com.mogo.cloud.netty.server; + +import static android.widget.Toast.LENGTH_SHORT; + +import android.net.nsd.NsdServiceInfo; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.cloud.R; +import com.mogo.cloud.netty.LogBean; +import com.mogo.telematic.NetworkUtils; +import com.mogo.telematic.server.NSDServer; +import com.mogo.telematic.server.bean.ClientChanel; +import com.mogo.telematic.server.netty.NettyServerListener; +import com.mogo.telematic.server.netty.NettyTcpServer; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; + +public class NettyServerActivity extends AppCompatActivity implements View.OnClickListener, NettyServerListener { + + private static final String TAG = "NettyServerActivity"; + + private Button mClearLog; + private Button mSendBtn; + private Button startServer; + private EditText mSendET; + private RecyclerView mSendList; + private RecyclerView mReceList; + + private LogAdapter mSendLogAdapter = new LogAdapter(); + private LogAdapter mReceLogAdapter = new LogAdapter(); + private TextView receiveTv; + + List clientChanelArray = new ArrayList<>(); //储存客户端通道信息 + private Spinner mSpinner; + private CustomSpinnerAdapter spinnerAdapter; + private TextView mIpView; + + private NSDServer mNsdServer; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_netty_server); + + findViews(); + initData(); + initListener(); + } + + private void initListener() { + + spinnerAdapter = new CustomSpinnerAdapter(this, clientChanelArray); + + mSpinner.setAdapter(spinnerAdapter); + mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + ClientChanel clientChanel = spinnerAdapter.getItem(position); + Toast.makeText(NettyServerActivity.this, "onItemSelected:" + clientChanel.getClientIp(), Toast.LENGTH_LONG).show(); + NettyTcpServer.getInstance().selectorChannel(clientChanel.getChannel()); + } + + @Override + public void onNothingSelected(AdapterView parent) { + NettyTcpServer.getInstance().selectorChannel(null); + Toast.makeText(NettyServerActivity.this, "onNothingSelected", Toast.LENGTH_LONG).show(); + } + }); + } + + private void initData() { + LinearLayoutManager manager1 = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + mSendList.setLayoutManager(manager1); + mSendList.setAdapter(mSendLogAdapter); + + LinearLayoutManager manager2 = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + mReceList.setLayoutManager(manager2); + mReceList.setAdapter(mReceLogAdapter); + + } + + private void findViews() { + mSendList = findViewById(R.id.send_list); + mReceList = findViewById(R.id.rece_list); + mSendET = findViewById(R.id.send_et); + mSendBtn = findViewById(R.id.send_btn); + mClearLog = findViewById(R.id.clear_log); + startServer = findViewById(R.id.startServer); + receiveTv = findViewById(R.id.receiveTv); + mSpinner = findViewById(R.id.spinner); + mIpView = findViewById(R.id.tv_ip); + + startServer.setOnClickListener(this); + mSendBtn.setOnClickListener(this); + mClearLog.setOnClickListener(this); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + mIpView.setText(NetworkUtils.getIPAddress(this) + "(切换网络后不会刷新!)"); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.startServer: + startServer(); + break; + + case R.id.send_btn: + if (!NettyTcpServer.getInstance().isServerStart()) { + Toast.makeText(getApplicationContext(), "未连接,请先连接", LENGTH_SHORT).show(); + } else { + final String msg = mSendET.getText().toString(); + if (TextUtils.isEmpty(msg.trim())) { + return; + } + NettyTcpServer.getInstance().sendMsgToServer(msg, new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture channelFuture) throws Exception { + if (channelFuture.isSuccess()) { //4 + Log.d(TAG, "Write auth successful"); + logSend(msg); + } else { + Log.d(TAG, "Write auth error"); + } + } + }); + mSendET.setText(""); + } + break; + + case R.id.clear_log: + mReceLogAdapter.getDataList().clear(); + mSendLogAdapter.getDataList().clear(); + mReceLogAdapter.notifyDataSetChanged(); + mSendLogAdapter.notifyDataSetChanged(); + break; + } + } + + private void startServer() { + NettyTcpServer nettyTcpServer = NettyTcpServer.getInstance(); +// nettyTcpServer.setPacketSeparator("#"); + if (!nettyTcpServer.isServerStart()) { + nettyTcpServer.setListener(NettyServerActivity.this); + + nettyTcpServer.start(); + } else { + NettyTcpServer.getInstance().disconnect(); + } + } + + private void registerNsdServer() { + new Thread(nsdServerRunnable).start(); + } + + @Override + public void onMessageResponseServer(String msg, String uniqueId) { +// Log.e(TAG,"onMessageResponseServer:ChannelId:"+uniqueId); + logRece(msg); + } + + @Override + public void onChannelConnect(final Channel channel) { + + String socketStr = channel.remoteAddress().toString(); + final ClientChanel clientChanel = new ClientChanel(socketStr, channel, channel.id().asShortText()); + + synchronized (clientChanelArray) { + clientChanelArray.add(clientChanel); + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(NettyServerActivity.this, clientChanel.getClientIp() + " 建立连接", Toast.LENGTH_LONG).show(); + spinnerAdapter.notifyDataSetChanged(); + } + }); + } + + } + + @Override + public void onChannelDisConnect(Channel channel) { + Log.e(TAG, "onChannelDisConnect:ChannelId" + channel.id().asShortText()); + + for (int i = 0; i < clientChanelArray.size(); i++) { + final ClientChanel clientChanel = clientChanelArray.get(i); + if (clientChanel.getShortId().equals(channel.id().asShortText())) { + + /** + * 当Spinner里第一个item被remove,不会触发onItemSelected,(因为 mSelectedPosition != mOldSelectedPosition) + */ + if (i == 0) { + try { + Field field = AdapterView.class.getDeclaredField("mOldSelectedPosition"); + field.setAccessible(true); //设置mOldSelectedPosition可访问 + field.setInt(mSpinner, AdapterView.INVALID_POSITION); //设置mOldSelectedPosition的值 + } catch (Exception e) { + e.printStackTrace(); + } + } + + synchronized (clientChanelArray) { + clientChanelArray.remove(clientChanel); + runOnUiThread(new Runnable() { + @Override + public void run() { + Log.e(TAG, "disconncect " + clientChanel.getClientIp()); + Toast.makeText(NettyServerActivity.this, clientChanel.getClientIp() + " 断开连接", Toast.LENGTH_LONG).show(); + spinnerAdapter.notifyDataSetChanged(); + } + }); + } + + return; + } + } + + } + + @Override + public void onStartServer() { + registerNsdServer(); + Log.e(TAG, "onStartServer"); + runOnUiThread(new Runnable() { + @Override + public void run() { + startServer.setText("stopServer"); + } + }); + } + + @Override + public void onStopServer() { + Log.e(TAG, "onStopServer"); + if (mNsdServer != null) { + mNsdServer.stopNSDServer(); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + startServer.setText("startServer"); + } + }); + } + + + private void logSend(String log) { + LogBean logBean = new LogBean(System.currentTimeMillis(), log); + mSendLogAdapter.getDataList().add(0, logBean); + runOnUiThread(new Runnable() { + @Override + public void run() { + mSendLogAdapter.notifyDataSetChanged(); + } + }); + + } + + private void logRece(String log) { + LogBean logBean = new LogBean(System.currentTimeMillis(), log); + mReceLogAdapter.getDataList().add(0, logBean); + runOnUiThread(new Runnable() { + @Override + public void run() { + mReceLogAdapter.notifyDataSetChanged(); + } + }); + } + + /** + * 服务器端注册一个可供NSD探测到的网络 Ip 地址,便于给展示叫号机连接此socket + */ + Runnable nsdServerRunnable = new Runnable() { + @Override + public void run() { + + mNsdServer = new NSDServer(); + mNsdServer.startNSDServer(NettyServerActivity.this, NettyTcpServer.SERVER_NAME, NettyTcpServer.SERVER_PORT); + + mNsdServer.setRegisterState(new NSDServer.IRegisterState() { + @Override + public void onServiceRegistered(NsdServiceInfo serviceInfo) { + Log.i(TAG, "已注册服务onServiceRegistered: " + serviceInfo.toString()); + //已经注册可停止该服务 +// nsdServer.stopNSDServer(); + } + @Override + public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + + } + @Override + public void onServiceUnregistered(NsdServiceInfo serviceInfo) { + + } + @Override + public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + + } + }); + } + }; +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6148872..8b9a3d6 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -112,6 +112,14 @@ android:text="查看周边可直播车" android:visibility="visible" /> +