diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/ConnectStatusAdapter.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/ConnectStatusAdapter.java index 5c6cd96285..95a4bffe09 100644 --- a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/ConnectStatusAdapter.java +++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/adapter/ConnectStatusAdapter.java @@ -1,6 +1,7 @@ package com.zhidao.adas.client.adapter; import android.annotation.SuppressLint; +import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -38,7 +39,8 @@ public class ConnectStatusAdapter extends BaseAdapter
" + data.status; + viewHolder.editText.setText(Html.fromHtml(str)); viewHolder.editText.setTextColor(mContext.getResources().getColor(data.color)); } diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java index d6a73ea144..440c1c01eb 100644 --- a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java +++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/MainActivity.java @@ -17,6 +17,7 @@ import android.text.Html; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; +import android.util.Pair; import android.view.View; import android.view.WindowManager; import android.widget.AdapterView; @@ -43,6 +44,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator; import com.google.protobuf.TextFormat; import com.mogo.support.obu.ObuScene; +import com.mogo.support.obu.constants.MogoObuConstants; import com.zhidao.adas.client.App; import com.zhidao.adas.client.BuildConfig; import com.zhidao.adas.client.DataDistribution; @@ -79,6 +81,7 @@ import com.zhidao.support.adas.high.common.Constants.IPC_CONNECTION_STATUS; import com.zhidao.support.adas.high.common.CupidLogUtils; import com.zhidao.support.adas.high.common.ProtocolStatus; import com.zhidao.support.adas.high.common.ReceiveTimeoutManager; +import com.zhidao.support.adas.high.common.RegexUtils; import com.zhjt.mogo.adas.data.bean.AutopilotStatistics; import org.jetbrains.annotations.NotNull; @@ -139,7 +142,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas private RecyclerView infoFragment; private TextView tvConnectState; private ScheduledExecutorService mExecutorServiceConfigTimer; - + private PingFloatWindow pingFloatWindow; private final List titleFragmentData = new ArrayList<>(); private final List titleBtnData = new ArrayList<>(); @@ -291,6 +294,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas private void initView() { + ImageView btn_ping = findViewById(R.id.btn_ping); include_title = findViewById(R.id.include_title); etIp = findViewById(R.id.et_ip); background = findViewById(R.id.background); @@ -589,6 +593,67 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas } else { background.setVisibility(View.GONE); } + btn_ping.setSelected(pingFloatWindow != null); + btn_ping.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (pingFloatWindow == null) { + Pair pair = getInputIp(); + if (pair != null) { + pingFloatWindow = new PingFloatWindow(MainActivity.this, pair.first); + int[] location = new int[2]; + btn_ping.getLocationOnScreen(location); + int x = location[0]; + int y = location[1]; + pingFloatWindow.showFloatWindow(x + (btn_ping.getWidth() / 2) - 260, btn_ping.getY() + btn_ping.getHeight()); + } + + } else { + pingFloatWindow.hideFloatWindow(); + pingFloatWindow = null; + } + btn_ping.setSelected(pingFloatWindow != null); + } + }); + } + + + private Pair getInputIp() { + String address = etIp.getText().toString().trim(); + if (TextUtils.isEmpty(address)) { + Toast.makeText(this, "请输入OBU地址", Toast.LENGTH_SHORT).show(); + return null; + } + String tempIp; + int tempPort; + if (address.contains(":")) { + String[] temp = address.split(":"); + if (temp.length < 2) { + Toast.makeText(this, "地址输入有误", Toast.LENGTH_SHORT).show(); + return null; + } + tempIp = temp[0]; + try { + tempPort = Integer.parseInt(temp[1]); + if (tempPort <= 0 || tempPort > 65535) { + Toast.makeText(this, "端口范围溢出", Toast.LENGTH_SHORT).show(); + return null; + } + } catch (NumberFormatException e) { + e.printStackTrace(); + Toast.makeText(this, "端口不合法", Toast.LENGTH_SHORT).show(); + return null; + } + + } else { + tempIp = address; + tempPort = MogoObuConstants.DEFAULT_OBU_PORT; + } + if (!RegexUtils.isIP(tempIp)) { + Toast.makeText(this, "地址不合法", Toast.LENGTH_SHORT).show(); + return null; + } + return new Pair<>(tempIp, tempPort); } private void showListPopupWindow() { diff --git a/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/PingFloatWindow.java b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/PingFloatWindow.java new file mode 100644 index 0000000000..146c5aeeac --- /dev/null +++ b/app_ipc_monitoring/src/main/java/com/zhidao/adas/client/ui/PingFloatWindow.java @@ -0,0 +1,310 @@ +package com.zhidao.adas.client.ui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.Message; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; + +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.support.obu.common.L; +import com.zhidao.adas.client.R; +import com.zhidao.adas.client.adapter.ConnectStatusAdapter; +import com.zhidao.adas.client.bean.IPCConnectState; +import com.zhidao.adas.client.utils.MyLinearLayoutManager; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +/** + * ping命令窗口 + */ +public class PingFloatWindow implements View.OnTouchListener { + private static final String TAG = PingFloatWindow.class.getSimpleName(); + private static final int WHAT_STATE = 8; + private final Activity mContext; + private WindowManager.LayoutParams mWindowParams; + private WindowManager mWindowManager; + + private View mFloatLayout; + private float mInViewX; + private float mInViewY; + private float mDownInScreenX; + private float mDownInScreenY; + private float mInScreenX; + private float mInScreenY; + private RecyclerView rv_status; + private ConnectStatusAdapter adapter; + private final List list = new ArrayList<>(); + private final String ip; + private Timer timer; + + public PingFloatWindow(Activity context, String ip) { + this.mContext = context; + this.ip = ip; + initFloatWindow(); + initHandler(); + pingTimer(true); + } + + private void pingTimer(boolean isStart) { + if (isStart) { + if (timer == null) { + timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + ping(); + } + }, 100L, 2500L);//延时 + } + } else { + if (timer != null) { + timer.cancel(); + timer = null; + } + } + } + + private void ping() { + Process p; + try { + //ping -c 3 -w 100 中 ,-c 是指ping的次数 3是指ping 3次 ,-w 100 以秒为单位指定超时间隔,是指超时时间为100秒 + p = Runtime.getRuntime().exec("ping -c 1 -w 2 " + ip); + int status = p.waitFor(); + InputStream input = p.getInputStream(); + BufferedReader in = new BufferedReader(new InputStreamReader(input)); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = in.readLine()) != null) { + builder.append(line).append("\n"); + } + String str = "IP:" + ip + " 是否可以连通:" + (status == 0 ? "是" : "否"); + L.i(TAG, builder.toString() + str); + add(str, status == 0); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + private void add(String str, boolean isConnect) { + + int color; + if (isConnect) { + color = R.color.connect_status_connected; + } else { + color = R.color.connect_status_disconnected; + } + IPCConnectState status = new IPCConnectState(str, color); + list.add(0, status); + if (list.size() > 100) { + list.remove(list.size() - 1); + } + Message msg = Message.obtain(); + msg.what = WHAT_STATE; + getHandler().sendMessage(msg); + } + + + public void refreshView() { + if (adapter != null) { + adapter.refreshView(); + } + } + + private void initRV() { + //创建默认的线性LayoutManager 横向的GridLayoutManager + MyLinearLayoutManager linearLayoutManager = new MyLinearLayoutManager(mContext); +// linearLayoutManager.setStackFromEnd(true);//列表再底部开始展示,反转后由上面开始展示 +// linearLayoutManager.setReverseLayout(true);//列表翻转 + rv_status.setLayoutManager(linearLayoutManager); + //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 + rv_status.setHasFixedSize(false); + rv_status.setNestedScrollingEnabled(false); + adapter = new ConnectStatusAdapter(); + adapter.setHasStableIds(true); + rv_status.setAdapter(adapter); + adapter.setData(list); + } + + private void initFloatWindow() { + LayoutInflater inflater = LayoutInflater.from(mContext); + if (inflater == null) + return; + mFloatLayout = (View) inflater.inflate(R.layout.layout_float, null); + rv_status = mFloatLayout.findViewById(R.id.rv_status); + mFloatLayout.setOnTouchListener(this); + initRV(); + mWindowParams = new WindowManager.LayoutParams(); +// mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); +// if (Build.VERSION.SDK_INT >= 26) {//8.0新特性 +// mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +// }else{ +// mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; +// } + + mWindowManager = mContext.getWindowManager(); + + mWindowParams.format = PixelFormat.RGBA_8888; + mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mWindowParams.gravity = Gravity.START | Gravity.TOP; + mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; + mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + mWindowParams.alpha = 0.9F; + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + return floatLayoutTouch(motionEvent); + } + + private boolean floatLayoutTouch(MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + // 获取相对View的坐标,即以此View左上角为原点 + mInViewX = motionEvent.getX(); + mInViewY = motionEvent.getY(); + // 获取相对屏幕的坐标,即以屏幕左上角为原点 + mDownInScreenX = motionEvent.getRawX(); + mDownInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext); + mInScreenX = motionEvent.getRawX(); + mInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext); + break; + case MotionEvent.ACTION_MOVE: + // 更新浮动窗口位置参数 + mInScreenX = motionEvent.getRawX(); + mInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext); + mWindowParams.x = (int) (mInScreenX - mInViewX); + mWindowParams.y = (int) (mInScreenY - mInViewY); + // 手指移动的时候更新小悬浮窗的位置 + mWindowManager.updateViewLayout(mFloatLayout, mWindowParams); + break; + case MotionEvent.ACTION_UP: + // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。 + if (mDownInScreenX == mInScreenX && mDownInScreenY == mInScreenY) { + + } + break; + } + return true; + } + + public void showFloatWindow(float x, float y) { + if (mFloatLayout.getParent() == null) { +// DisplayMetrics metrics = new DisplayMetrics(); + // 默认固定位置,靠屏幕右边缘的中间 +// mWindowManager.getDefaultDisplay().getMetrics(metrics); + mWindowParams.x = (int) x; + mWindowParams.y = (int) (y); + mWindowManager.addView(mFloatLayout, mWindowParams); + } + } + + + public void hideFloatWindow() { + pingTimer(false); + if (getHandler() != null) { + getHandler().removeCallbacksAndMessages(null); + } + if (mFloatLayout.getParent() != null) + mWindowManager.removeView(mFloatLayout); + + } + + public void setFloatLayoutAlpha(boolean alpha) { + if (alpha) + mFloatLayout.setAlpha((float) 0.5); + else + mFloatLayout.setAlpha(1); + } + + private int sbar = -1; + + // 获取系统状态栏高度 + public int getSysBarHeight(Context contex) { + if (sbar == -1) { + Class c; + Object obj; + Field field; + int x; + sbar = 0; + try { + c = Class.forName("com.android.internal.R$dimen"); + obj = c.newInstance(); + field = c.getField("status_bar_height"); + x = Integer.parseInt(field.get(obj).toString()); + sbar = contex.getResources().getDimensionPixelSize(x); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + return sbar; + } + + + private BaseHandler mBaseHandler; + + /** + * 初始化一个Handler,如果需要使用Handler,先调用此方法, + * 然后可以使用postRunnable(Runnable runnable), + * sendMessage在handleMessage(Message msg)中接收msg + */ + public void initHandler() { + mBaseHandler = new BaseHandler(this); + } + + /** + * 返回Handler,在此之前确定已经调用initHandler() + * + * @return Handler + */ + public Handler getHandler() { + return mBaseHandler; + } + + + /** + * 同Handler 的 handleMessage, + * getHandler.sendMessage,发送的Message在此接收 + * 在此之前确定已经调用initHandler() + * + * @param msg + */ + protected void handleMessage(Message msg) { + switch (msg.what) { + case WHAT_STATE: + refreshView(); + break; + } + } + + + protected static class BaseHandler extends Handler { + private final WeakReference mObjects; + + public BaseHandler(PingFloatWindow mPresenter) { + mObjects = new WeakReference(mPresenter); + } + + @Override + public void handleMessage(Message msg) { + PingFloatWindow mPresenter = mObjects.get(); + if (mPresenter != null) + mPresenter.handleMessage(msg); + } + } +} diff --git a/app_ipc_monitoring/src/main/res/drawable/ic_ping.xml b/app_ipc_monitoring/src/main/res/drawable/ic_ping.xml new file mode 100644 index 0000000000..7f2d08030c --- /dev/null +++ b/app_ipc_monitoring/src/main/res/drawable/ic_ping.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app_ipc_monitoring/src/main/res/drawable/ic_ping_selected.xml b/app_ipc_monitoring/src/main/res/drawable/ic_ping_selected.xml new file mode 100644 index 0000000000..b012d739a9 --- /dev/null +++ b/app_ipc_monitoring/src/main/res/drawable/ic_ping_selected.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app_ipc_monitoring/src/main/res/drawable/selector_ping.xml b/app_ipc_monitoring/src/main/res/drawable/selector_ping.xml new file mode 100644 index 0000000000..5f7eb6e4d1 --- /dev/null +++ b/app_ipc_monitoring/src/main/res/drawable/selector_ping.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app_ipc_monitoring/src/main/res/layout/item_main.xml b/app_ipc_monitoring/src/main/res/layout/item_main.xml index 52fbb751ab..c1c6b623fd 100644 --- a/app_ipc_monitoring/src/main/res/layout/item_main.xml +++ b/app_ipc_monitoring/src/main/res/layout/item_main.xml @@ -17,9 +17,9 @@ + + \ No newline at end of file