Merge branch 'dev_robotaxi-d-app-module_266_220425_2.6.6' of gitlab.zhidaoauto.com:zhjt/AndroidApp/MoGoEagleEye into dev_robotaxi-d-app-module_266_220425_2.6.6

This commit is contained in:
wangmingjun
2022-04-27 14:31:04 +08:00
53 changed files with 1662 additions and 225 deletions

View File

@@ -1,3 +1,5 @@
import java.text.SimpleDateFormat
apply plugin: 'com.android.application'
android {
@@ -24,6 +26,15 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
//插入构建时间
buildTypes.each {
//设置时间格式
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd.HHmmss", Locale.getDefault())
//获取当前时间
Date curDate = new Date(System.currentTimeMillis())
String buildTime = formatter.format(curDate)
it.buildConfigField 'String', 'BUILD_TIME', "\"${buildTime}\""
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -44,13 +55,14 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation rootProject.ext.dependencies.material
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.androidxappcompat
implementation 'androidx.recyclerview:recyclerview:1.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation "com.google.code.gson:gson:2.8.9"
implementation rootProject.ext.dependencies.gson
implementation project(':libraries:mogo-adas')
implementation project(':core:mogo-core-data')
implementation project(':core:mogo-core-utils')

View File

@@ -29,6 +29,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
@@ -54,6 +55,11 @@
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".ui.HelpActivity"
android:theme="@style/AppTheme.NoActionBar">
</activity>
</application>
</manifest>

View File

@@ -10,6 +10,7 @@ import com.zhidao.adas.client.bean.GlobalPathResp;
import com.zhidao.adas.client.bean.GnssInfo;
import com.zhidao.adas.client.bean.MogoReportMessage;
import com.zhidao.adas.client.bean.PerceptionTrafficLight;
import com.zhidao.adas.client.bean.PredictionObstacleTrajectory;
import com.zhidao.adas.client.bean.RecordPanel;
import com.zhidao.adas.client.bean.TrackedObjects;
import com.zhidao.adas.client.bean.Trajectory;
@@ -98,6 +99,7 @@ public class DataDistribution {
public final List<String> listAutopilotState = new ArrayList<>();
public final List<String> listMogoReportMessage = new ArrayList<>();
public final List<String> listPerceptionTrafficLight = new ArrayList<>();
public final List<String> listPredictionObstacleTrajectory = new ArrayList<>();
public final List<String> listBasicInfoReq = new ArrayList<>();
public final List<String> listRecordPanel = new ArrayList<>();
public final List<String> listGlobalPathResp = new ArrayList<>();
@@ -114,7 +116,8 @@ public class DataDistribution {
}
private String onTransmit(String time, BaseInfo data) {
String str = cutDown(data.toString());
String temp = data.toString();
String str = cutDown(temp);
if (data instanceof Trajectory) {
listTrajectory.add(0, time + str);
if (listTrajectory.size() > LIST_SIZE) {
@@ -205,6 +208,19 @@ public class DataDistribution {
// for (OnAdasClientListener listener : listeners) {
// listener.onPerceptionTrafficLight((PerceptionTrafficLight) data);
// }
// }
} else if (data instanceof PredictionObstacleTrajectory) {
listPredictionObstacleTrajectory.add(0, time + str);
if (listPredictionObstacleTrajectory.size() > LIST_SIZE) {
listPredictionObstacleTrajectory.remove(listPredictionObstacleTrajectory.size() - 1);
}
if (listener != null) {
listener.onRefresh();
}
// if (!listeners.isEmpty()) {
// for (OnAdasClientListener listener : listeners) {
// listener.onRefresh();
// }
// }
} else if (data instanceof BasicInfoReq) {
listBasicInfoReq.add(0, time + str);
@@ -295,7 +311,7 @@ public class DataDistribution {
// }
}
return str;
return temp;
}
private class WriteThread implements Runnable {

View File

@@ -0,0 +1,67 @@
package com.zhidao.adas.client.adapter;
import android.annotation.SuppressLint;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import com.zhidao.adas.client.R;
import com.zhidao.adas.client.base.BaseAdapter;
import com.zhidao.adas.client.base.BaseViewHolder;
import com.zhidao.adas.client.bean.IPCConnectState;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* 连接状态
*/
public class ConnectStatusAdapter extends BaseAdapter<IPCConnectState, ConnectStatusAdapter.ViewHolder> {
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ", Locale.getDefault());
private static final String POS = "%03d. ";
public void refreshView() {
// notifyItemChanged(mDatas.size()-1,0);
notifyItemRangeChanged(0, getItemCount());
}
@Override
public long getItemId(int position) {
return position;
}
@SuppressLint("SetTextI18n")
@Override
protected void onBindDataToItem(ViewHolder viewHolder, IPCConnectState data, int position) {
viewHolder.id.setText(String.format(Locale.getDefault(), POS, getItemCount() - position));
viewHolder.editText.setText(sdf.format(new Date(data.time)) + "\n" + data.status);
viewHolder.editText.setTextColor(mContext.getResources().getColor(data.color));
}
@Override
protected View getItemViewResource(ViewGroup viewGroup) {
return LayoutInflater.from(mContext).inflate(R.layout.item_status, viewGroup, false);
}
@Override
protected ViewHolder getViewHolder(View view) {
return new ViewHolder(view, this);
}
class ViewHolder extends BaseViewHolder<ConnectStatusAdapter> {
EditText editText;
TextView id;
public ViewHolder(View itemView, ConnectStatusAdapter adapter) {
super(itemView, adapter);
editText = itemView.findViewById(R.id.log);
id = itemView.findViewById(R.id.id);
}
}
}

View File

@@ -2,14 +2,38 @@ package com.zhidao.adas.client.base;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.zhidao.adas.client.ui.MainActivity;
import java.lang.ref.WeakReference;
public abstract class BaseActivity extends AppCompatActivity {
private BaseHandler mBaseHandler;
private Toast toast;
protected void showToastCenter(String msg) {
showToastCenter(msg, Toast.LENGTH_SHORT);
}
protected void showToastCenter(String msg, int duration) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (toast != null) {
toast.cancel();
toast = null;
}
toast = Toast.makeText(BaseActivity.this, "", duration); //如果有居中显示需求
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setText(msg);
toast.show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();

View File

@@ -3,6 +3,7 @@ package com.zhidao.adas.client.bean;
import androidx.annotation.ColorRes;
public class IPCConnectState {
public final long time;
public final String status;
@ColorRes
public final int color;
@@ -10,5 +11,6 @@ public class IPCConnectState {
public IPCConnectState(String status, @ColorRes int color) {
this.status = status;
this.color = color;
time = System.currentTimeMillis();
}
}

View File

@@ -0,0 +1,22 @@
package com.zhidao.adas.client.bean;
import com.google.protobuf.TextFormat;
import mogo.telematics.pad.MessagePad;
import prediction.Prediction;
public class PredictionObstacleTrajectory extends BaseInfo {
public final Prediction.mPredictionObjects bean;
public PredictionObstacleTrajectory(MessagePad.Header header, Prediction.mPredictionObjects bean) {
super("接收", bean.getSerializedSize(), header);
this.bean = bean;
}
@Override
public String toString() {
return super.toString() + TextFormat.printer().escapingNonAscii(false).printToString(bean);
}
}

View File

@@ -0,0 +1,181 @@
package com.zhidao.adas.client.ui;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.DisplayMetrics;
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.zhidao.adas.client.R;
import com.zhidao.adas.client.adapter.ConnectStatusAdapter;
import com.zhidao.adas.client.adapter.DataShowAdapter;
import com.zhidao.adas.client.bean.IPCConnectState;
import com.zhidao.adas.client.utils.MyLinearLayoutManager;
import java.lang.reflect.Field;
import java.util.List;
/**
* @author xuxinchao
* @description
* @since: 2022/4/20
*/
public class FloatWindow implements View.OnTouchListener {
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 List<IPCConnectState> list;
public FloatWindow(Activity context, List<IPCConnectState> list) {
this.mContext = context;
this.list = list;
initFloatWindow();
}
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 y) {
if (mFloatLayout.getParent() == null) {
DisplayMetrics metrics = new DisplayMetrics();
// 默认固定位置,靠屏幕右边缘的中间
mWindowManager.getDefaultDisplay().getMetrics(metrics);
mWindowParams.x = metrics.widthPixels;
mWindowParams.y = (int) (y);
mWindowManager.addView(mFloatLayout, mWindowParams);
}
}
public void hideFloatWindow() {
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;
}
}

View File

@@ -0,0 +1,22 @@
package com.zhidao.adas.client.ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import com.zhidao.adas.client.R;
import com.zhidao.adas.client.base.BaseActivity;
public class HelpActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_help);
showToastCenter("点击屏幕任意位置,退出帮助页面");
}
public void onBack(View view) {
finish();
}
}

View File

@@ -146,6 +146,9 @@ public class InfoFragment extends BaseFragment {
case Constants.TITLE.RECEIVE_PERCEPTION_TRAFFIC_LIGHT:
adapter.setData(DataDistribution.getInstance().listPerceptionTrafficLight);
break;
case Constants.TITLE.RECEIVE_PREDICTION_OBSTACLE_TRAJECTORY:
adapter.setData(DataDistribution.getInstance().listPredictionObstacleTrajectory);
break;
case Constants.TITLE.RECEIVE_ERROR:
adapter.setData(DataDistribution.getInstance().listErrorData);
break;

View File

@@ -4,6 +4,7 @@ import static com.mogo.telematic.MogoProtocolMsg.NORMAL_DATA;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Message;
@@ -57,6 +58,7 @@ import com.zhidao.adas.client.bean.IPCConnectState;
import com.zhidao.adas.client.bean.MogoReportMessage;
import com.zhidao.adas.client.bean.MySSHResult;
import com.zhidao.adas.client.bean.PerceptionTrafficLight;
import com.zhidao.adas.client.bean.PredictionObstacleTrajectory;
import com.zhidao.adas.client.bean.RecordPanel;
import com.zhidao.adas.client.bean.TrackedObjects;
import com.zhidao.adas.client.bean.Trajectory;
@@ -76,7 +78,6 @@ 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.recorder.RecordDataManager;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -92,13 +93,14 @@ import io.netty.channel.Channel;
import mogo.telematics.pad.MessagePad;
import mogo_msg.MogoReportMsg;
import perception.TrafficLightOuterClass;
import prediction.Prediction;
import record_cache.RecordPanelOuterClass;
public class MainActivity extends BaseActivity implements OnAdasListener, OnAdasConnectStatusListener, BaseAdapter.OnItemClickListener<String> {
private final static String TAG = MainActivity.class.getSimpleName();
private static final int WHAT_IPC_IP = 0x00;
private static final int WHAT_DRIVER_IP = 0x01;
private static final int WHATIPC_CONNECT_STATE = 0x02;
private static final int WHAT_IPC_CONNECT_STATE = 0x02;
private EditText etIp;
private ImageView role;
private ImageView tvIp;
@@ -124,7 +126,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
private final List<String> titleFragmentData = new ArrayList<>();
private final List<String> titleBtnData = new ArrayList<>();
private final List<IPCConnectState> connectStatusList = new ArrayList<>();
private InfoTitleAdapter btnAdapter;
private InfoTitleAdapter fragmentAdapter;
@@ -141,6 +143,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
private InfoFragment errorFragment;
private InfoFragment reportMessageFragment;
private InfoFragment perceptionTrafficLightFragment;
private InfoFragment predictionObstacleTrajectoryFragment;
private VersionFragment versionFragment;
private FragmentManager manager;
private FragmentTransaction transaction;
@@ -151,7 +154,8 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
private int connectStatus;
private AutoPilotModeDialog autoPilotModeDialog;
private ListPopupWindow listPopupWindow;
private FloatWindow floatWindow;
private View include_title;
// @Override
// protected void onStart() {
// super.onStart();
@@ -207,6 +211,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
private void initView() {
include_title = findViewById(R.id.include_title);
etIp = findViewById(R.id.et_ip);
role = findViewById(R.id.role);
line = findViewById(R.id.line);
@@ -278,7 +283,6 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
etIp.setSelection(ip.length());
}
// infoTitleList.add("录音测试");
//初始化fragment
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
@@ -379,6 +383,13 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
showLocalIP();
}
});
title.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
startActivity(new Intent(MainActivity.this, HelpActivity.class));
return true;
}
});
tvIp.setOnClickListener(new View.OnClickListener() {
@Override
@@ -393,6 +404,18 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
}
}
});
tvConnectState.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (floatWindow == null) {
floatWindow = new FloatWindow(MainActivity.this, connectStatusList);
floatWindow.showFloatWindow(include_title.getY() + include_title.getHeight());
} else {
floatWindow.hideFloatWindow();
floatWindow = null;
}
}
});
}
private void showListPopupWindow() {
@@ -431,6 +454,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
titleFragmentData.add(Constants.TITLE.RECEIVE_AUTOPILOT_STATE);
titleFragmentData.add(Constants.TITLE.RECEIVE_REPORT_MESSAGE);
titleFragmentData.add(Constants.TITLE.RECEIVE_PERCEPTION_TRAFFIC_LIGHT);
titleFragmentData.add(Constants.TITLE.RECEIVE_PREDICTION_OBSTACLE_TRAJECTORY);
titleFragmentData.add(Constants.TITLE.RECEIVE_CAR_CONFIG_RESP);
titleFragmentData.add(Constants.TITLE.RECEIVE_RECORD_RESULT);
titleFragmentData.add(Constants.TITLE.RECEIVE_GLOBAL_PATH_RESP);
@@ -446,7 +470,6 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
titleBtnData.add("数据采集5秒");
titleBtnData.add("数据采集start");
titleBtnData.add("数据采集end");
titleBtnData.add("录音测试");
titleBtnData.add("发送信号灯");
titleBtnData.add("自动驾驶限速");
titleBtnData.add("重启Docker");
@@ -588,6 +611,14 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
transaction.commit();
}
break;
case Constants.TITLE.RECEIVE_PREDICTION_OBSTACLE_TRAJECTORY:
if (predictionObstacleTrajectoryFragment == null)
predictionObstacleTrajectoryFragment = new InfoFragment(data);
if (!predictionObstacleTrajectoryFragment.isVisible()) {
transaction.replace(R.id.fl_info, predictionObstacleTrajectoryFragment);
transaction.commit();
}
break;
case Constants.TITLE.RECEIVE_CAR_CONFIG_RESP:
AdasManager.getInstance().sendCarConfigReq();
if (versionFragment == null)
@@ -630,36 +661,52 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
}
}
private String onUpdateConnectStateView() {
String status;
private int getStatusColor(int connectStatus) {
int color;
switch (connectStatus) {
case IPC_CONNECTION_STATUS.CONNECTED:
status = "已连接";
color = R.color.connect_status_connected;
break;
default:
case IPC_CONNECTION_STATUS.DISCONNECTED:
status = "未连接";
color = R.color.connect_status_disconnected;
break;
case IPC_CONNECTION_STATUS.CONNECTING:
status = "连接中";
color = R.color.connect_status_connecting;
break;
case IPC_CONNECTION_STATUS.SEARCH_ADDRESS:
status = "搜索IP";
color = R.color.connect_status_search_address;
break;
case IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS:
status = "未找到";
color = R.color.connect_status_disconnecting;
break;
}
return color;
}
private String onUpdateConnectStateView() {
String status;
switch (connectStatus) {
case IPC_CONNECTION_STATUS.CONNECTED:
status = "已连接";
break;
default:
case IPC_CONNECTION_STATUS.DISCONNECTED:
status = "未连接";
break;
case IPC_CONNECTION_STATUS.CONNECTING:
status = "连接中";
break;
case IPC_CONNECTION_STATUS.SEARCH_ADDRESS:
status = "搜索IP";
break;
case IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS:
status = "未找到";
break;
}
Message msg = Message.obtain();
msg.obj = new IPCConnectState(status, color);
msg.what = WHATIPC_CONNECT_STATE;
msg.obj = new IPCConnectState(status, getStatusColor(connectStatus));
msg.what = WHAT_IPC_CONNECT_STATE;
getHandler().sendMessage(msg);
return status;
}
@@ -720,6 +767,12 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
DataDistribution.getInstance().addData(base);
}
@Override
public void onPredictionObstacleTrajectory(MessagePad.Header header, Prediction.mPredictionObjects predictionObjects) {
PredictionObstacleTrajectory base = new PredictionObstacleTrajectory(header, predictionObjects);
DataDistribution.getInstance().addData(base);
}
@Override
public void onBasicInfoReq(MessagePad.Header header, MessagePad.BasicInfoReq basicInfoReq) {
BasicInfoReq info = new BasicInfoReq(header, basicInfoReq);
@@ -766,27 +819,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
}
private Toast toast;
public void showToastCenter(String msg) {
showToastCenter(msg, Toast.LENGTH_SHORT);
}
public void showToastCenter(String msg, int duration) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (toast != null) {
toast.cancel();
toast = null;
}
toast = Toast.makeText(MainActivity.this, "", duration); //如果有居中显示需求
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setText(msg);
toast.show();
}
});
}
private void initAdas() {
@@ -857,7 +890,6 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
AdasManager.getInstance().create(options, this);
AdasManager.getInstance().setOnAdasListener(this);
// AdasManager.getInstance().setOnAdasConnectStatusListener(this);
if (BuildConfig.IS_CLIENT) {
/*—————————————作为乘客端———————————*/
@@ -881,18 +913,6 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
}
@Override
protected void onPause() {
super.onPause();
// AdasManager.getInstance().pause();
}
@Override
protected void onResume() {
super.onResume();
// AdasManager.getInstance().resume();
}
@Override
protected void onDestroy() {
super.onDestroy();
@@ -906,7 +926,12 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
@Override
public void onConnectionIPCStatus(int ipcConnectionStatus, String failedMsg) {
public void onConnectionIPCStatus(int ipcConnectionStatus, String reason) {
Log.i(TAG, "连接状态=" + (reason == null ? "主动断开连接" : reason));
connectStatusList.add(0, new IPCConnectState(reason == null ? "主动断开连接" : reason, getStatusColor(ipcConnectionStatus)));
if (connectStatusList.size() > 100) {
connectStatusList.remove(connectStatusList.size() - 1);
}
connectStatus = ipcConnectionStatus;
String status = onUpdateConnectStateView();
if (connectStatus == IPC_CONNECTION_STATUS.CONNECTED) {
@@ -917,10 +942,6 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
Constants.addIpcUsedIps(this, ips, tem);
}
} else if (connectStatus == IPC_CONNECTION_STATUS.DISCONNECTED) {
if (!TextUtils.isEmpty(failedMsg)) {
status += " failedMsg=" + failedMsg;
showToastCenter("连接失败:" + failedMsg);
}
getHandler().sendEmptyMessage(WHAT_IPC_IP);
}
// LogSave.getInstance().saveLog("连接状态", status);
@@ -1012,12 +1033,6 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
CupidLogUtils.w(TAG, "AutopilotRecord===>send:" + bEnd);
break;
case 6:
//录音测试
CupidLogUtils.w(TAG, "录音测试");
RecordDataManager.getInstance().init(MainActivity.this, "1234567", "", 22, "", "");
RecordDataManager.getInstance().record();
break;
case 7:
//发送信号灯
MessagePad.TrafficLightStatus left = MessagePad.TrafficLightStatus.newBuilder()
.setPhaseNo("1")
@@ -1041,7 +1056,7 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
.build();
AdasManager.getInstance().sendTrafficLightData("10038", 26.848153, 112.574883, "180.0", "SN", 100413, -4, 201, 0, detail);
break;
case 8:
case 7:
//速度设置
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("自动驾驶限速");
@@ -1068,27 +1083,27 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
builder.show();//显示Dialog对话框
break;
case 9:
case 8:
//重启Docker
AdasManager.getInstance().rebootAPDocker();
break;
case 10:
case 9:
//重启IPC
AdasManager.getInstance().rebootIPC();
break;
case 11:
case 10:
//关机
AdasManager.getInstance().shutdownIPC();
break;
case 12:
case 11:
//采集类型
AdasManager.getInstance().sendRecordCause(recordKey, recordFileName, "1", "变道有干扰");
break;
case 13:
case 12:
//打开演示模式
AdasManager.getInstance().sendDemoModeReq(1);
break;
case 14:
case 13:
//关闭演示模式
AdasManager.getInstance().sendDemoModeReq(0);
break;
@@ -1107,7 +1122,10 @@ public class MainActivity extends BaseActivity implements OnAdasListener, OnAdas
ipcIp.setVisibility(View.VISIBLE);
ipcIp.setText("司机IP" + NSDNettyManager.getInstance().getConnServerIp());
break;
case WHATIPC_CONNECT_STATE:
case WHAT_IPC_CONNECT_STATE:
if (floatWindow != null) {
floatWindow.refreshView();
}
IPCConnectState status = (IPCConnectState) msg.obj;
tvConnectState.setText(status.status);
tvConnectState.setTextColor(getResources().getColor(status.color));

View File

@@ -167,10 +167,11 @@ public class VersionFragment extends BaseFragment {
list.add(new Config("最大自动驾驶限速:", adasConfig == null ? null : adasConfig.getMaxSpeedLimit() + "m/s"));
list.add(new Config("最小加速度:", adasConfig == null ? null : adasConfig.getMinAcceleration() + "m/s²"));
list.add(new Config("最大加速度:", adasConfig == null ? null : adasConfig.getMaxAcceleration() + "m/s²"));
list.add(new Config("IPC通信协议版本:", adasConfig == null ? null : String.valueOf(adasConfig.getProtocolVersion().getNumber())));
list.add(new Config("IPC通信协议版本:", adasConfig == null ? null : String.valueOf(adasConfig.getProtocolVersionValue())));
list.add(new Config("APP通信协议版本:", String.valueOf(AdasManager.getInstance().getProtocolVersion())));
}
list.add(new Config("ADAS LIB版本:", AdasManager.getInstance().getAdasVersion()));
list.add(new Config("APP构建时间:", BuildConfig.BUILD_TIME));
adapter.setData(list);
}

View File

@@ -150,6 +150,7 @@ public class Constants {
String RECEIVE_AUTOPILOT_STATE = "自动驾驶状态";
String RECEIVE_REPORT_MESSAGE = "监控事件";
String RECEIVE_PERCEPTION_TRAFFIC_LIGHT = "感知红绿灯";
String RECEIVE_PREDICTION_OBSTACLE_TRAJECTORY = "他车轨迹预测";
// String RECEIVE_BASIC_INFO_REQ = "自动驾驶设备基础信息请求";
String RECEIVE_CAR_CONFIG_RESP = "信息与配置";

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FAFFFFFF" />
<stroke
android:width="0.8dp"
android:color="#A140E0D0" />
<!-- 圆角 -->
<corners android:radius="6dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="onBack"
android:scaleType="fitXY"
android:src="@drawable/help"
tools:context=".ui.HelpActivity" />

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--测试列表Item-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="3dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="3dp"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal">
<TextView
android:id="@+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#999999"
android:textSize="12sp" />
<EditText
android:id="@+id/log"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:cursorVisible="false"
android:focusable="false"
android:textColor="#ff0000"
android:textSize="12sp" />
</LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_float"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_status"
android:layout_width="260dp"
android:layout_height="280dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp" />
</LinearLayout>

View File

@@ -28,4 +28,7 @@
<!--是否模糊-->
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

View File

@@ -47,6 +47,7 @@ import mogo.telematics.pad.MessagePad
import mogo.telematics.pad.MessagePad.TrackedObject
import mogo_msg.MogoReportMsg
import perception.TrafficLightOuterClass
import prediction.Prediction
import record_cache.RecordPanelOuterClass
/**
@@ -214,6 +215,13 @@ class MoGoAdasListenerImpl : OnAdasListener {
}
override fun onPredictionObstacleTrajectory(
header: MessagePad.Header?,
predictionObjects: Prediction.mPredictionObjects?
) {
//他车轨迹预测
}
override fun onBasicInfoReq(
header: MessagePad.Header,
basicInfoReq: MessagePad.BasicInfoReq?

View File

@@ -22,13 +22,16 @@ import com.mogo.eagle.core.data.enums.SidePattern
import com.mogo.eagle.core.data.enums.WarningDirectionEnum
import com.mogo.eagle.core.data.notice.NoticeNormalData
import com.mogo.eagle.core.data.notice.NoticeTrafficStylePushData
import com.mogo.eagle.core.data.report.ReportEntity
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotRecordListener
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
import com.mogo.eagle.core.function.api.hmi.IMoGoHmiViewProxy
import com.mogo.eagle.core.function.api.hmi.view.IViewLimitingVelocity
import com.mogo.eagle.core.function.api.hmi.view.IViewNotification
import com.mogo.eagle.core.function.api.hmi.view.IViewTrafficLight
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWaringProvider
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager
import com.mogo.eagle.core.function.call.check.CallerCheckManager
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
@@ -44,16 +47,19 @@ import com.mogo.eagle.core.function.hmi.ui.camera.CameraListView
import com.mogo.eagle.core.function.hmi.ui.notice.NoticeBannerView
import com.mogo.eagle.core.function.hmi.ui.notice.NoticeNormalBannerView
import com.mogo.eagle.core.function.hmi.ui.setting.DebugSettingView
import com.mogo.eagle.core.function.hmi.ui.setting.ReportListFloatWindow
import com.mogo.eagle.core.function.hmi.ui.tools.AutoPilotAndCheckView
import com.mogo.eagle.core.function.hmi.ui.widget.V2XNotificationView
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_HMI
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.eagle.core.utilcode.util.TimeUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.module.common.enums.EventTypeEnum
import kotlinx.android.synthetic.main.fragment_hmi.*
import kotlinx.coroutines.*
import mogo_msg.MogoReportMsg
import record_cache.RecordPanelOuterClass
import java.util.*
@@ -68,7 +74,8 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
IMoGoWaringProvider,
IMoGoHmiViewProxy,
MoGoHmiContract.View,
IMoGoAutopilotRecordListener {
IMoGoAutopilotRecordListener,
IMoGoAutopilotStatusListener {
private val TAG = "MoGoHmiFragment"
// DebugSettingView
@@ -101,6 +108,10 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
// V2X预警弹窗 View 代理
private var mViewNotification: IViewNotification? = null
//工控机节点上报列表
private var reportList = arrayListOf<ReportEntity>()
//工控机上报列表悬浮窗
private var reportListFloatWindow: ReportListFloatWindow?=null
override fun vipIdentification(visible: Boolean) {
ThreadUtils.runOnUiThread {
@@ -143,6 +154,7 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
CallerAutopilotRecordListenerManager.addListener(TAG, this)
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
/*// TODO 这里后面需要改成独立进程通讯后台获取YUV
view.postDelayed({
@@ -174,6 +186,7 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
override fun onDestroyView() {
super.onDestroyView()
CallerAutopilotRecordListenerManager.removeListener(TAG)
CallerAutoPilotStatusListenerManager.removeListener(TAG)
}
@@ -386,7 +399,7 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
*/
override fun toggleDebugView() {
CallerLogger.d("$M_HMI$TAG", "长按显示状态工具栏")
context?.let {
activity?.let {
if (mDebugSettingViewFloat != null) {
WarningFloat.dismiss(mDebugSettingViewFloat!!.config.floatTag, false)
mDebugSettingViewFloat = null
@@ -394,6 +407,18 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
} else {
if (mDebugSettingView == null) {
mDebugSettingView = DebugSettingView(it)
mDebugSettingView?.setClickListener(object: DebugSettingView.ClickListener{
override fun showReportListWindow(show: Boolean) {
if(show){
//打开工控机上报列表
reportListFloatWindow = ReportListFloatWindow(it)
reportListFloatWindow?.showFloatWindow()
}else{
//关闭工控机上报列表
reportListFloatWindow?.hideFloatWindow()
}
}
})
}
var side = SidePattern.RIGHT
var gravity = Gravity.RIGHT
@@ -979,6 +1004,23 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
}
/**
* 工控机监控节点上报
*/
override fun onAutopilotGuardian(guardianInfo: MogoReportMsg.MogoReportMessage?) {
ThreadUtils.runOnUiThread{
guardianInfo?.let {
if(reportList.size>20){
reportList.removeLast()
}
reportList.add(0,
ReportEntity(TimeUtils.millis2String(System.currentTimeMillis()),
it.src,it.level,it.msg,it.code,it.resultList,it.actionsList))
reportListFloatWindow?.refreshData(reportList)
}
}
}
override fun onDestroy() {
super.onDestroy()
CallerLogger.d("$M_HMI$TAG", "onDestroy")

View File

@@ -0,0 +1,133 @@
package com.mogo.eagle.core.function.hmi.ui.setting
import android.app.Activity
import android.graphics.PixelFormat
import android.util.DisplayMetrics
import android.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.data.gnss.AccelerationEntity
import com.mogo.eagle.core.function.hmi.R
import java.lang.reflect.Field
/**
* @author XuXinChao
* @description 可拖拽实时加速度面板
* @since: 2022/4/21
*/
class AccelerationFloatWindow constructor(activity: Activity) : View.OnTouchListener{
private var mActivity: Activity = activity
private var mWindowParams: WindowManager.LayoutParams? = null
private var mWindowManager: WindowManager? = null
private lateinit var rvAccelerationList: RecyclerView
private var accelerationListAdapter: AccelerationListAdapter?=null
private lateinit var mFloatLayout: View
private var mInViewX = 0f
private var mInViewY = 0f
private var mDownInScreenX = 0f
private var mDownInScreenY = 0f
private var mInScreenX = 0f
private var mInScreenY = 0f
init {
initFloatWindow();
}
private fun initFloatWindow() {
mFloatLayout = LayoutInflater.from(mActivity).inflate(R.layout.view_acceleration_float, null) as View
mFloatLayout.setOnTouchListener(this)
rvAccelerationList= mFloatLayout.findViewById(R.id.rvAccelerationList)
mWindowParams = 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 = mActivity.windowManager
mWindowParams?.let {
it.format = PixelFormat.RGBA_8888
it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
it.gravity = Gravity.START or Gravity.TOP
it.width = 600
it.height = WindowManager.LayoutParams.WRAP_CONTENT
it.alpha = 0.8f
}
accelerationListAdapter= AccelerationListAdapter(mActivity)
rvAccelerationList.layoutManager = LinearLayoutManager(mActivity,
LinearLayoutManager.VERTICAL,false)
rvAccelerationList.adapter = accelerationListAdapter
rvAccelerationList.isNestedScrollingEnabled = false
}
fun refreshData(data:List<AccelerationEntity>){
accelerationListAdapter?.setDada(data)
accelerationListAdapter?.notifyDataSetChanged()
}
override fun onTouch(v: View?, motionEvent: MotionEvent?): Boolean {
when (motionEvent?.action) {
MotionEvent.ACTION_DOWN -> {
// 获取相对View的坐标即以此View左上角为原点
mInViewX = motionEvent.x
mInViewY = motionEvent.y
// 获取相对屏幕的坐标,即以屏幕左上角为原点
mDownInScreenX = motionEvent.rawX
mDownInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
mInScreenX = motionEvent.rawX
mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
}
MotionEvent.ACTION_MOVE -> {
// 更新浮动窗口位置参数
mInScreenX = motionEvent.rawX
mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
mWindowParams!!.x = (mInScreenX - mInViewX).toInt()
mWindowParams!!.y = (mInScreenY - mInViewY).toInt()
// 手指移动的时候更新小悬浮窗的位置
mWindowManager!!.updateViewLayout(mFloatLayout, mWindowParams)
}
// MotionEvent.ACTION_UP -> // 如果手指离开屏幕时xDownInScreen和xInScreen相等且yDownInScreen和yInScreen相等则视为触发了单击事件。
// if (mDownInScreenX === mInScreenX && mDownInScreenY === mInScreenY) {
// }
}
return true
}
fun showFloatWindow() {
if (mFloatLayout.parent == null) {
val metrics = DisplayMetrics()
// 默认固定位置,靠屏幕右边缘的中间
mWindowManager!!.defaultDisplay.getMetrics(metrics)
mWindowParams!!.x = metrics.widthPixels
mWindowParams!!.y = metrics.heightPixels / 2 - getSysBarHeight(mActivity)
mWindowManager!!.addView(mFloatLayout, mWindowParams)
}
}
fun hideFloatWindow() {
if (mFloatLayout.parent != null) mWindowManager!!.removeView(mFloatLayout)
}
// 获取系统状态栏高度
private fun getSysBarHeight(activity: Activity): Int {
val c: Class<*>
val obj: Any
val field: Field
val x: Int
var sbar = 0
try {
c = Class.forName("com.android.internal.R\$dimen")
obj = c.newInstance()
field = c.getField("status_bar_height")
x = field.get(obj).toString().toInt()
sbar = activity.resources.getDimensionPixelSize(x)
} catch (e1: Exception) {
e1.printStackTrace()
}
return sbar
}
}

View File

@@ -0,0 +1,48 @@
package com.mogo.eagle.core.function.hmi.ui.setting
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.data.gnss.AccelerationEntity
import com.mogo.eagle.core.function.hmi.R
/**
* @author XuXinChao
* @description 实时加速度列表适配器
* @since: 2022/4/20
*/
class AccelerationListAdapter(context: Context) :
RecyclerView.Adapter<AccelerationListAdapter.AccelerationListHolder>() {
private var context: Context? = context
private var data:List<AccelerationEntity>? = null
fun setDada( data: List<AccelerationEntity>?){
this.data = data
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccelerationListHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_acceleration_detail, parent, false)
return AccelerationListHolder(view)
}
override fun onBindViewHolder(holder: AccelerationListHolder, position: Int) {
data?.let { it ->
val accelerationEntity = it[position]
holder.tvMoment.text = accelerationEntity.moment
holder.tvAcceleration.text = accelerationEntity.acceleration
}
}
override fun getItemCount() = data?.size ?: 0
class AccelerationListHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var tvMoment: TextView = itemView.findViewById(R.id.tvMoment)
var tvAcceleration: TextView = itemView.findViewById(R.id.tvAcceleration)
}
}

View File

@@ -1,6 +1,7 @@
package com.mogo.eagle.core.function.hmi.ui.setting
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.os.Build
@@ -24,6 +25,7 @@ import com.mogo.eagle.core.data.constants.MoGoConfig
import com.mogo.eagle.core.data.deva.chain.ChainConstant
import com.mogo.eagle.core.data.deva.scene.SceneModule
import com.mogo.eagle.core.data.enums.TrafficTypeEnum
import com.mogo.eagle.core.data.gnss.AccelerationEntity
import com.mogo.eagle.core.data.map.MogoLocation
import com.mogo.eagle.core.data.obu.ObuStatusInfo
import com.mogo.eagle.core.data.upgrade.UpgradeVersionEntity
@@ -66,6 +68,7 @@ import mogo.telematics.pad.MessagePad
import mogo_msg.MogoReportMsg
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.abs
/**
* @author xiaoyuzhou
@@ -91,6 +94,11 @@ class DebugSettingView @JvmOverloads constructor(
private var mAutoPilotStatusInfo: AutopilotStatusInfo? = null
private var mGnssInfo: MessagePad.GnssInfo? = null
private var accelerationFloatWindow: AccelerationFloatWindow?=null
private var accelerationList = arrayListOf<AccelerationEntity>()
private var accelerationIsShow: Boolean = false //实时加速度面板是否展示
private var accelerationThresholdNum: Double = 0.0
// 感知识别「已知类型」数据个数
private var mIdentifyDataSize = 0
@@ -141,6 +149,8 @@ class DebugSettingView @JvmOverloads constructor(
private var lastVisualAngleMode: VisualAngleMode? = null
private var clickListener: ClickListener? = null
init {
LayoutInflater.from(context).inflate(R.layout.view_debug_setting, this, true)
initView()
@@ -604,6 +614,11 @@ class DebugSettingView @JvmOverloads constructor(
//初始化ADAS日志开关状态
tbADASLog.isChecked = CallerAutoPilotManager.isEnableLog()
//查看上报历史列表
tbReportMore.setOnCheckedChangeListener { _, isChecked ->
clickListener?.showReportListWindow(isChecked)
}
}
/**
@@ -966,6 +981,33 @@ class DebugSettingView @JvmOverloads constructor(
}
}
/**
* 实时加速度面板控制
*/
tbOpenAcceleration.setOnCheckedChangeListener { _, isChecked ->
if(isChecked){
//打开实时加速度面板
accelerationFloatWindow = context?.let { AccelerationFloatWindow(it as Activity) }
accelerationFloatWindow?.showFloatWindow()
etThreshold.visibility = View.VISIBLE
btnThresholdDefine.visibility = View.VISIBLE
}else{
//关闭实时加速度面板
accelerationFloatWindow?.hideFloatWindow()
etThreshold.visibility = View.GONE
btnThresholdDefine.visibility = View.GONE
}
accelerationIsShow = isChecked
}
btnThresholdDefine.setOnClickListener {
try{
accelerationThresholdNum = etThreshold.text.toString().toDouble()
}catch(e:java.lang.Exception){
ToastUtils.showShort("请输入正确的阈值")
}
}
}
/**
@@ -1599,6 +1641,26 @@ class DebugSettingView @JvmOverloads constructor(
override fun onAutopilotCarStateData(gnssInfo: MessagePad.GnssInfo?) {
mGnssInfo = gnssInfo
//实时加速度列表
ThreadUtils.runOnUiThread{
if(accelerationIsShow){
if(accelerationList.size > 9){
accelerationList.removeLast()
}
gnssInfo?.acceleration?.let {
if(accelerationList.isEmpty()){
accelerationList.add(AccelerationEntity(TimeUtils.millis2String(System.currentTimeMillis(),TimeUtils.getHourMinSecondFormat()),it.toString()))
}
if(abs(it.minus(accelerationList.first().acceleration.toDouble())) > abs(accelerationThresholdNum)){
accelerationList.add(0, AccelerationEntity(TimeUtils.millis2String(System.currentTimeMillis(),TimeUtils.getHourMinSecondFormat()),it.toString()))
}
accelerationFloatWindow?.refreshData(accelerationList)
}
}
}
}
@RequiresApi(Build.VERSION_CODES.N)
@@ -1746,4 +1808,12 @@ class DebugSettingView @JvmOverloads constructor(
}
}
fun setClickListener(clickListener: ClickListener) {
this.clickListener = clickListener
}
interface ClickListener{
fun showReportListWindow(show: Boolean)
}
}

View File

@@ -0,0 +1,90 @@
package com.mogo.eagle.core.function.hmi.ui.setting
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.data.report.ReportEntity
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager
import com.mogo.eagle.core.function.hmi.R
/**
* @author XuXinChao
* @description 工控机上报列表适配器
* @since: 2022/4/13
*/
class ReportListAdapter(context: Context) :
RecyclerView.Adapter<ReportListAdapter.ReportListHolder>() {
private var context: Context? = context
private var data:List<ReportEntity>? = null
public fun setDada( data: List<ReportEntity>?){
this.data = data
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReportListHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_report_detail, parent, false)
return ReportListHolder(view)
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ReportListHolder, position: Int) {
data?.let { it ->
val reportEntity = it[position]
reportEntity.let {
holder.tvReportTime.text = it.time
holder.tvReportSrc.text = "src:${it.src}"
holder.tvReportLevel.text = "level:${it.level}"
holder.tvReportMsg.text = "msg:${it.msg}"
holder.tvReportCode.text = "code:${it.code}"
var resultStr = "result:"
for (result in it.resultList) {
resultStr = "$resultStr$result${CallerAutoPilotManager.getReportResultDesc(result)} "
}
holder.tvReportResult.text = resultStr
var actionStr = "action:"
for (action in it.actionsList) {
actionStr = "$actionStr$action${CallerAutoPilotManager.getReportActionDesc(action)} "
}
holder.tvReportActions.text = actionStr
if ("error" == it.level) {
//字体为红色,吐司提示
holder.tvReportSrc.setTextColor(Color.RED)
holder.tvReportLevel.setTextColor(Color.RED)
holder.tvReportMsg.setTextColor(Color.RED)
holder.tvReportCode.setTextColor(Color.RED)
holder.tvReportResult.setTextColor(Color.RED)
holder.tvReportActions.setTextColor(Color.RED)
} else {
holder.tvReportSrc.setTextColor(Color.WHITE)
holder.tvReportLevel.setTextColor(Color.WHITE)
holder.tvReportMsg.setTextColor(Color.WHITE)
holder.tvReportCode.setTextColor(Color.WHITE)
holder.tvReportResult.setTextColor(Color.WHITE)
holder.tvReportActions.setTextColor(Color.WHITE)
}
}
}
}
override fun getItemCount() = data?.size ?: 0
class ReportListHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var tvReportTime: TextView = itemView.findViewById(R.id.tvReportTime)
var tvReportSrc: TextView = itemView.findViewById(R.id.tvReportSrc)
var tvReportLevel: TextView = itemView.findViewById(R.id.tvReportLevel)
var tvReportMsg: TextView = itemView.findViewById(R.id.tvReportMsg)
var tvReportCode: TextView = itemView.findViewById(R.id.tvReportCode)
var tvReportResult: TextView = itemView.findViewById(R.id.tvReportResult)
var tvReportActions: TextView = itemView.findViewById(R.id.tvReportActions)
}
}

View File

@@ -0,0 +1,125 @@
package com.mogo.eagle.core.function.hmi.ui.setting
import android.app.Activity
import android.graphics.PixelFormat
import android.util.DisplayMetrics
import android.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.data.report.ReportEntity
import com.mogo.eagle.core.function.hmi.R
import java.lang.reflect.Field
/**
* @author XuXinChao
* @description 工控机上报列表面板
* @since: 2022/4/13
*/
class ReportListFloatWindow constructor(activity: Activity) : View.OnTouchListener{
private var mActivity: Activity = activity
private var mWindowParams: WindowManager.LayoutParams? = null
private var mWindowManager: WindowManager? = null
private lateinit var rvReportList: RecyclerView
private var reportListAdapter: ReportListAdapter?=null
private lateinit var mFloatLayout: View
private var mInViewX = 0f
private var mInViewY = 0f
private var mDownInScreenX = 0f
private var mDownInScreenY = 0f
private var mInScreenX = 0f
private var mInScreenY = 0f
init {
initFloatWindow();
}
private fun initFloatWindow() {
mFloatLayout = LayoutInflater.from(mActivity).inflate(R.layout.view_report_list, null) as View
mFloatLayout.setOnTouchListener(this)
rvReportList= mFloatLayout.findViewById(R.id.rv_report_list)
mWindowParams = WindowManager.LayoutParams()
mWindowManager = mActivity.windowManager
mWindowParams?.let {
it.format = PixelFormat.RGBA_8888
it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
it.gravity = Gravity.START or Gravity.TOP
it.width = 800
it.height = 1000
it.alpha = 0.9f
}
reportListAdapter= ReportListAdapter(mActivity)
rvReportList.layoutManager = LinearLayoutManager(mActivity,
LinearLayoutManager.VERTICAL,false)
rvReportList.adapter = reportListAdapter
}
fun refreshData(data:List<ReportEntity>){
reportListAdapter?.setDada(data)
reportListAdapter?.notifyDataSetChanged()
}
override fun onTouch(v: View?, motionEvent: MotionEvent?): Boolean {
when (motionEvent?.action) {
MotionEvent.ACTION_DOWN -> {
// 获取相对View的坐标即以此View左上角为原点
mInViewX = motionEvent.x
mInViewY = motionEvent.y
// 获取相对屏幕的坐标,即以屏幕左上角为原点
mDownInScreenX = motionEvent.rawX
mDownInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
mInScreenX = motionEvent.rawX
mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
}
MotionEvent.ACTION_MOVE -> {
// 更新浮动窗口位置参数
mInScreenX = motionEvent.rawX
mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
mWindowParams!!.x = (mInScreenX - mInViewX).toInt()
mWindowParams!!.y = (mInScreenY - mInViewY).toInt()
// 手指移动的时候更新小悬浮窗的位置
mWindowManager!!.updateViewLayout(mFloatLayout, mWindowParams)
}
// MotionEvent.ACTION_UP -> // 如果手指离开屏幕时xDownInScreen和xInScreen相等且yDownInScreen和yInScreen相等则视为触发了单击事件。
// if (mDownInScreenX === mInScreenX && mDownInScreenY === mInScreenY) {
// }
}
return true
}
fun showFloatWindow() {
if (mFloatLayout.parent == null) {
val metrics = DisplayMetrics()
// 默认固定位置,靠屏幕右边缘的中间
mWindowManager!!.defaultDisplay.getMetrics(metrics)
mWindowParams!!.x = metrics.widthPixels
mWindowParams!!.y = metrics.heightPixels / 2 - getSysBarHeight(mActivity)
mWindowManager!!.addView(mFloatLayout, mWindowParams)
}
}
fun hideFloatWindow() {
if (mFloatLayout.parent != null) mWindowManager!!.removeView(mFloatLayout)
}
// 获取系统状态栏高度
private fun getSysBarHeight(activity: Activity): Int {
val c: Class<*>
val obj: Any
val field: Field
val x: Int
var sbar = 0
try {
c = Class.forName("com.android.internal.R\$dimen")
obj = c.newInstance()
field = c.getField("status_bar_height")
x = field.get(obj).toString().toInt()
sbar = activity.resources.getDimensionPixelSize(x)
} catch (e1: Exception) {
e1.printStackTrace()
}
return sbar
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tvMoment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/foreground_wtf"
android:gravity="center_horizontal"
/>
<TextView
android:id="@+id/tvAcceleration"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:textColor="@color/foreground_wtf"
android:gravity="center_horizontal"
/>
</LinearLayout>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tvReportTime"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tvReportSrc"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/tvReportLevel"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvReportMsg"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvReportCode"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvReportResult"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvReportActions"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
</LinearLayout>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="500dp"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/icon_drag"
android:padding="15dp"
android:layout_gravity="center_horizontal"
/>
<com.mogo.eagle.core.widget.RoundConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/dialog_bg_color"
app:roundLayoutRadius="10dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvAccelerationList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
/>
</com.mogo.eagle.core.widget.RoundConstraintLayout>
</LinearLayout>

View File

@@ -12,109 +12,145 @@
android:layout_width="match_parent"
android:layout_height="@dimen/dp_350"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent">
app:layout_constraintBottom_toBottomOf="parent"
tools:visibility="visible">
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="match_parent">
<View
android:id="@+id/vReportLine"
android:layout_width="match_parent"
android:layout_height="6dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toTopOf="parent" />
<ToggleButton
android:id="@+id/tbReportMore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:drawableEnd="@drawable/icon_right"
android:drawablePadding="5dp"
android:gravity="center"
android:padding="10dp"
android:textOff="打开历史"
android:textOn="关闭历史"
android:textSize="@dimen/dp_24"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/vReportLine" />
<TextView
android:id="@+id/tvReportSrc"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/tbReportMore"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tbReportMore"
app:layout_constraintTop_toBottomOf="@id/vReportLine"
app:layout_constraintTop_toTopOf="@id/tbReportMore" />
<View
android:id="@+id/vReportSrcLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tbReportMore" />
<TextView
android:id="@+id/tvReportLevel"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportSrcLine" />
<View
android:id="@+id/vReportLevelLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tvReportLevel" />
<TextView
android:id="@+id/tvReportMsg"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportLevelLine" />
<View
android:id="@+id/vReportMsgLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tvReportMsg" />
<TextView
android:id="@+id/tvReportCode"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportMsgLine" />
<View
android:id="@+id/vReportCodeLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tvReportCode" />
<TextView
android:id="@+id/tvReportResult"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportCodeLine" />
<View
android:id="@+id/vReportResultLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tvReportResult" />
<TextView
android:id="@+id/tvReportActions"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportResultLine" />
<View
android:id="@+id/vReportActionsLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tvReportActions" />
<TextView
android:id="@+id/tvReportSec"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportActionsLine" />
<View
android:id="@+id/vReportSecLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
android:background="#F0F0F0"
app:layout_constraintTop_toBottomOf="@id/tvReportSec" />
<TextView
android:id="@+id/tvReportNSec"
style="@style/DebugSettingText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
</LinearLayout>
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/vReportSecLine" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
@@ -221,7 +257,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/tvAppVersionName"
@@ -362,7 +399,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/tvServerEnvironment"
@@ -459,7 +497,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<ToggleButton
android:id="@+id/tbDomainController"
@@ -476,7 +515,8 @@
android:id="@+id/domainControllerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/tvAutopilotInfo"
@@ -660,7 +700,8 @@
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/btnSystemRestart"
app:layout_constraintTop_toBottomOf="@id/recordPackageDivider" />
app:layout_constraintTop_toBottomOf="@id/recordPackageDivider"
tools:visibility="visible" />
<Button
android:id="@+id/btnSystemRestart"
@@ -670,7 +711,8 @@
android:visibility="gone"
app:layout_constraintLeft_toRightOf="@id/btnSystemUpgrade"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/recordPackageDivider" />
app:layout_constraintTop_toBottomOf="@id/recordPackageDivider"
tools:visibility="visible" />
<TextView
@@ -719,7 +761,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/tvSteeringInfo"
@@ -762,7 +805,8 @@
android:id="@+id/obuControllerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<Button
android:id="@+id/btnSetObuIP"
@@ -844,7 +888,8 @@
android:id="@+id/eagleEyeControllerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<Button
android:id="@+id/btnBrakeThreshold"
@@ -952,7 +997,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<ToggleButton
android:id="@+id/tbChangeCurrentSkinMode"
@@ -1054,6 +1100,46 @@
android:textOff="关闭「SN绑定控制」"
android:textOn="打开「SN绑定控制」"
android:textSize="@dimen/dp_24" />
<ToggleButton
android:id="@+id/tbOpenAcceleration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_margin="2dp"
android:gravity="center"
android:textOff="打开「加速度面板」"
android:textOn="关闭「加速度面板」"
android:textSize="@dimen/dp_24" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/etThreshold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_margin="2dp"
android:background="@drawable/debug_setting_edit_bg"
android:gravity="center"
android:hint="过滤阈值"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textSize="14sp"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btnThresholdDefine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:layout_margin="2dp"
android:gravity="center"
android:text="设置加速度变化幅度过滤阈值"
android:textSize="@dimen/dp_24"
android:visibility="gone"
tools:visibility="visible" />
</GridLayout>
<ToggleButton
@@ -1071,7 +1157,8 @@
android:id="@+id/hdMapControllerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<Button
android:id="@+id/changesight_top_btn"
@@ -1276,6 +1363,7 @@
android:id="@+id/tbIsDemoMode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:padding="@dimen/dp_10"
android:textColor="#000"
android:textOff="开启美化模式"
@@ -1289,6 +1377,7 @@
android:id="@+id/tbIsDrawAutopilotTrajectoryData"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:padding="@dimen/dp_10"
android:textColor="#000"
android:textOff="强制绘制引导线"
@@ -1296,14 +1385,12 @@
android:textSize="@dimen/dp_24"
app:layout_constraintLeft_toRightOf="@id/tbIsDemoMode"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnOpenObuFusion"
/>
app:layout_constraintTop_toTopOf="@id/tbIsDemoMode" />
<ToggleButton
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:padding="@dimen/dp_10"
android:textColor="#000"
android:textOff="强制绘制路径规划"
@@ -1388,7 +1475,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/flLogControl"
@@ -1440,8 +1528,7 @@
android:gravity="center"
android:textOff="打开「网络」Log"
android:textOn="关闭「网络」Log"
android:textSize="@dimen/dp_24"
/>
android:textSize="@dimen/dp_24" />
<ToggleButton
android:id="@+id/tbObuLog"
@@ -1451,8 +1538,7 @@
android:gravity="center"
android:textOff="打开「OBU」Log"
android:textOn="关闭「OBU」Log"
android:textSize="@dimen/dp_24"
/>
android:textSize="@dimen/dp_24" />
</com.google.android.flexbox.FlexboxLayout>
@@ -1678,7 +1764,8 @@
android:id="@+id/apkCenterLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:id="@+id/ivApkSearch"

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="840px"
android:layout_height="584px"
android:orientation="vertical"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/icon_drag"
android:padding="15dp"
android:layout_gravity="center_horizontal"
/>
<com.mogo.eagle.core.widget.RoundConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dialog_bg_color"
app:roundLayoutRadius="10dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_report_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.mogo.eagle.core.widget.RoundConstraintLayout>
</LinearLayout>

View File

@@ -36,6 +36,9 @@ public class IdentifyDataDrawer {
*/
private static final ConcurrentHashMap<String, MessagePad.TrackedObject> mMarkersCaches = new ConcurrentHashMap<>();
/**
* kalman缓存数据
*/
private static final ConcurrentHashMap<String, KalmanFilter> algoCache = new ConcurrentHashMap<>();
/**
@@ -108,7 +111,7 @@ public class IdentifyDataDrawer {
MogoMarkerManager.getInstance(mContext)
.updateBatchMarkerPosition(filterList);
}
CallerLogger.INSTANCE.d(M_HMI + "arrow48", "mMarkersCaches : " + mMarkersCaches.size());
CallerLogger.INSTANCE.d(M_HMI + "arrow48", "mMarkersCaches : " + mMarkersCaches.size());
}
/**
@@ -130,16 +133,11 @@ public class IdentifyDataDrawer {
MessagePad.TrackedObject cacheData = mMarkersCaches.get(uuid);
if (cacheData != null) {
MessagePad.TrackedObject correctData;
//todo 进行修正
double correctHeading = kalmanCorrect(data);
if(correctHeading != cacheData.getHeading()){
CallerLogger.INSTANCE.d(M_HMI + "arrow48", "uuid: " + uuid + " , kalmanCorrect : " + correctHeading + " , 修正 上一帧 : " + cacheData.getHeading() + " , 当前帧 : " + data.getHeading());
}
correctData = data.toBuilder().setHeading(correctHeading).build();
correctData = kalmanCorrectData(data);
mFilterTrafficData.add(correctData);
//更新已存在的感知物体数据
mMarkersCaches.put(uuid, correctData);
}else{
} else {
mMarkersCaches.put(uuid, data);
}
trafficDataUuidList.add(uuid);
@@ -147,7 +145,8 @@ public class IdentifyDataDrawer {
return mFilterTrafficData;
}
private double kalmanCorrect(MessagePad.TrackedObject data) {
//todo 相信滤波的定位点做验证将原始data修改经纬度和航向角返回
private MessagePad.TrackedObject kalmanCorrectData(MessagePad.TrackedObject data) {
String uuid = "" + data.getUuid();
if (algoCache.containsKey(uuid)) {
Object o = algoCache.get(uuid);
@@ -159,18 +158,19 @@ public class IdentifyDataDrawer {
assert cacheTrackObj != null;
if (data.getSpeed() >= 1.5) {
double heading = MogoMap.getInstance().getMogoMap().getUIController().getAngle(cacheTrackObj.getLongitude(), cacheTrackObj.getLatitude(), lonLat[0], lonLat[1]);
CallerLogger.INSTANCE.d(M_HMI + "arrow48", " uuid : " + uuid + " , origin heading : " + data.getHeading() + " , correct heading : " + heading + " ---- " + (data.getHeading() - heading));
return heading;
double correct = Math.abs(heading - data.getHeading()) > 30 && Math.abs(heading - data.getHeading()) < 120 ? heading : data.getHeading();//todo test
CallerLogger.INSTANCE.d(M_HMI + "type : " + data.getType(), " uuid : " + uuid + " , origin H : " + data.getHeading() + " , cal H : " + heading + ", correct : " + correct + " , 使用滤波角度 : " + (Math.abs(heading - data.getHeading()) > 30 && Math.abs(heading - data.getHeading()) < 120));
return data.toBuilder().setHeading(heading).setLongitude(lonLat[0]).setLatitude(lonLat[1]).build();
} else {
return data.getHeading();
return data;
}
} else {
double r = 0.00005;
double r = 0.000005;
if (AdasRecognizedType.valueFrom(data.getType()) == AdasRecognizedType.classIdTrafficBus || AdasRecognizedType.valueFrom(data.getType()) == AdasRecognizedType.classIdTrafficTruck) {
r = 0.0001;
r = 0.00001;
}
algoCache.put(uuid, new KalmanFilter(data.getLongitude(), data.getLatitude(), r));
return data.getHeading();
return data;
}
}
@@ -185,3 +185,4 @@ public class IdentifyDataDrawer {
trafficDataUuidList.clear();
}
}

View File

@@ -45,6 +45,7 @@ dependencies {
implementation rootProject.ext.dependencies.androidxccorektx
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.localbroadcastmanager
implementation rootProject.ext.dependencies.arouter
implementation rootProject.ext.dependencies.rxandroid
implementation rootProject.ext.dependencies.flexbox

View File

@@ -0,0 +1,12 @@
package com.mogo.eagle.core.data.gnss
/**
* @author XuXinChao
* @description 实时加速度实例
* @since: 2022/4/20
*/
data class AccelerationEntity(
var moment: String,//时刻
var acceleration: String//加速度
) {
}

View File

@@ -0,0 +1,20 @@
package com.mogo.eagle.core.data.report
/**
* @author XuXinChao
* @description 工控机上报实例
* @since: 2022/4/13
*/
data class ReportEntity(
var time: String,//上报时间
var src: String,//消息来源
var level: String,//消息等级 error info
var msg: String,//研发自己看的信息;对标准日志来说就是日志内容
var code: String, //error日志中的错误原因这是一个类似宏的受约束字段用字符串的目的是便于排查问题时查看
var resultList: List<String>,//带来的后果例如pad无法启动驾驶远程驾驶无法启动等可供监控后台做错误分类pad无法理解code时也可参考此字段
var actionsList: List<String>,//试验性字段。消息发出者希望触发的动作例如触发短信报警自动创建工单要求pad弹框等
// var sec: Int,//秒
// var nsec: Int//纳秒 sec和nsec拼接起来是消息发送事件
) {
}

View File

@@ -39,6 +39,10 @@ public final class TimeUtils {
return getSafeDateFormat("yyyy-MM-dd HH:mm:ss");
}
public static SimpleDateFormat getHourMinSecondFormat(){
return getSafeDateFormat("HH:mm:ss");
}
@SuppressLint("SimpleDateFormat")
public static SimpleDateFormat getSafeDateFormat(String pattern) {
Map<String, SimpleDateFormat> sdfMap = SDF_THREAD_LOCAL.get();

View File

@@ -82,7 +82,7 @@ MOGO_LOCATION_VERSION=1.3.55
MOGO_TELEMATIC_VERSION=1.3.55
######## MogoAiCloudSDK Version ########
# 自研地图
MAP_SDK_VERSION=2.1.0.6
MAP_SDK_VERSION=2.1.0.6-1
MAP_SDK_OPERATION_VERSION=1.0.12
# websocket
WEBSOCKET_VERSION=1.1.7

View File

@@ -0,0 +1,84 @@
syntax = "proto2";
package geometry;
message Vector3 {
optional double x = 1;
optional double y = 2;
optional double z = 3;
}
message Vector3f {
optional float x = 1;
optional float y = 2;
optional float z = 3;
}
message Point2D {
optional double x = 1 [default = nan];
optional double y = 2 [default = nan];
}
message Point3D {
optional double x = 1 [default = nan];
optional double y = 2 [default = nan];
optional double z = 3 [default = nan];
}
message Trace {
optional double timestamp = 1;
optional Point3D position = 2;
optional Point3D velocity = 3;
optional Point3D acceleration = 4;
optional Point3D heading = 5;
}
message PointLLH {
// Longitude in degrees, ranging from -180 to 180.
optional double lon = 1 [default = nan];
// Latitude in degrees, ranging from -90 to 90.
optional double lat = 2 [default = nan];
// WGS-84 ellipsoid height in meters.
optional double height = 3 [default = 0.0];
}
message Point {
optional double x = 1;
optional double y = 2;
optional double z = 3;
}
message Quaternion {
optional double x = 1 [default = nan];
optional double y = 2 [default = nan];
optional double z = 3 [default = nan];;
optional double w = 4 [default = nan];
}
message Polygon {
repeated Point points = 1;
}
message Transform {
optional Vector3 translation = 1;
optional Quaternion rotation = 2;
}
//pose in free space, composed of position and orientation
message Pose {
optional Point position = 1;
optional Quaternion orientation = 2;
}
//acceleration in free space broken into its linear and angular parts
message Accel {
optional Vector3 linear = 1;
optional Vector3 angular = 2;
}
//velocity in free space broken into its linear and angular parts
message Twist {
optional Vector3 linear = 1;
optional Vector3 angular = 2;
}

View File

@@ -3,7 +3,7 @@ package mogo.telematics.pad;
enum ProtocolVersion{
Defaultver = 0;
CurrentVersion = 1; //每次修改proto文件增加1
CurrentVersion = 2; //每次修改proto文件增加1
}
enum MessageType
@@ -17,6 +17,7 @@ enum MessageType
MsgTypeAutopilotState = 0x10004; //自动驾驶状态
MsgTypeReportMessage = 0x10005; //监控事件报告
MsgTypePerceptionTrafficLight = 0x10006; //感知红绿灯
MsgTypePredictionObstacleTrajectory = 0x10007; //他车轨迹预测
MsgTypeBasicInfoReq = 0x10100; //自动驾驶设备基础信息请求
MsgTypeBasicInfoResp = 0x10101; //自动驾驶设备基础信息应答
@@ -124,6 +125,9 @@ message AutopilotState
// message definition for MessageType: MsgTypePerceptionTrafficLight
// refer to traffic_light.proto
// message definition for MessageType: MsgTypePredictionObstacleTrajectory
// refer to prediction.proto
// message definition for MessageType: MsgTypeBasicInfoReq
message BasicInfoReq
{
@@ -154,6 +158,8 @@ message RouteInfo{
double speedLimit = 6; //单位: km/h
uint32 vehicleType = 7;
bool isSpeakVoice = 8;
uint32 routeID = 9;
string routeName = 10;
}
message SetAutopilotModeReq

View File

@@ -0,0 +1,33 @@
syntax = "proto2";
package prediction;
// common
import "header.proto";
import "geometry.proto";
// estimated obstacle intent
message mPredictionObject {
optional int64 m_nid =1; //target id
optional int32 m_nquality =2; //target tracking life quality
optional int32 classtype =3; //target classtype
optional int32 m_preconfidence=4; //target predciton confidence
repeated geometry.Point prediction_trajectory = 5; //target prediction trajectory :vector : meter
repeated geometry.Point prediction_pose = 6; //targe prediciton pose vector angle:°
optional geometry.Vector3 objsize = 7; //length width height :meter
}
message mPredictionObjects {
optional common.Header header = 1;
optional int32 m_nnum0 =2; // all target number
optional int64 allcyclenum =3;//process cycle number
optional double m_ftime=4; //time stamp
optional double fdeltat=5; // deltatime prediciton time stamp default:0.1s
repeated mPredictionObject objs=6; //obj capcity
}

View File

@@ -360,6 +360,24 @@
*/
void onReportMessage(MessagePad.Header header, MogoReportMsg.MogoReportMessage mogoReportMessage);
~~~
~~~java
/**
* 感知红绿灯
*
* @param header 头
* @param trafficLights 感知红绿灯
*/
void onPerceptionTrafficLight(MessagePad.Header header, TrafficLightOuterClass.TrafficLights trafficLights);
~~~
~~~java
/**
* 他车轨迹预测
*
* @param header 头
* @param predictionObjects 他车轨迹预测数据
*/
void onPredictionObstacleTrajectory(MessagePad.Header header, Prediction.mPredictionObjects predictionObjects);
~~~
~~~java
/**
* 自动驾驶设备基础信息请求
@@ -450,9 +468,10 @@
* 与工控机链接状态变化
*
* @param ipcConnectionStatus {@link Constants.IPC_CONNECTION_STATUS}
* @param failedMsg 连接异常信息
* @param reason 连接信息 需要判null
* 如果ipcConnectionStatus==Constants.IPC_CONNECTION_STATUS.DISCONNECTED&&reason==null 表示主动断开连接
*/
void onConnectionIPCStatus(@Define.IPCConnectionStatus int ipcConnectionStatus, String failedMsg);
void onConnectionIPCStatus(@Define.IPCConnectionStatus int ipcConnectionStatus, @Nullable String reason);
~~~
## OnMultiDeviceListener

View File

@@ -71,7 +71,7 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.mogochainbase
//okhttp3的依赖
implementation 'com.squareup.okhttp3:okhttp:3.12.3'
@@ -85,10 +85,10 @@ dependencies {
// implementation 'com.google.protobuf:protobuf-java-util:3.6.1'
implementation 'com.jcraft:jsch:0.1.55'
// api project(path: ':lib_recorder')
api "com.zhidao.support.recorder:recorder:1.0.0.3"
// api "com.zhidao.support.recorder:recorder:1.0.0.3"
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation project(':libraries:mogo-adas-data')
} else {
implementation project(':libraries:mogo-adas-data')
}

View File

@@ -17,7 +17,6 @@ import com.zhidao.support.adas.high.bean.SSHResult;
import com.zhidao.support.adas.high.common.Base64;
import com.zhidao.support.adas.high.common.Constants;
import com.zhidao.support.adas.high.common.CupidLogUtils;
import com.zhidao.support.adas.high.common.Define;
import com.zhidao.support.adas.high.common.DigitalTrans;
import com.zhidao.support.adas.high.common.IPCFixationIPHelper;
import com.zhidao.support.adas.high.common.MessageType;
@@ -40,8 +39,8 @@ import com.zhjt.service.chain.TracingConstants;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;
import mogo.telematics.pad.MessagePad;
import okio.ByteString;
@@ -67,8 +66,7 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
/**
* 与工控机链接状态
*/
@Define.IPCConnectionStatus
private int ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.DISCONNECTED;
private final AtomicInteger ipcConnectionStatus = new AtomicInteger(Constants.IPC_CONNECTION_STATUS.DISCONNECTED);
/**
@@ -111,16 +109,16 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
@Override
public void onStartFindIP() {
if (adasConnectStatusListener != null) {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.SEARCH_ADDRESS;
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, null);
ipcConnectionStatus.set(Constants.IPC_CONNECTION_STATUS.SEARCH_ADDRESS);
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus.get(), "正在搜索IP");
}
}
@Override
public void onStopFindIP() {
if (adasConnectStatusListener != null) {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.DISCONNECTED;
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, null);
ipcConnectionStatus.set(Constants.IPC_CONNECTION_STATUS.DISCONNECTED);
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus.get(), "停止搜索IP");
}
}
@@ -356,12 +354,8 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
public void connect() {
//当是司机屏才启用
if (!adasOptions.isClient()) {
if (ipcConnectionStatus == Constants.IPC_CONNECTION_STATUS.DISCONNECTED ||
ipcConnectionStatus == Constants.IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS) {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.SEARCH_ADDRESS;
if (adasConnectStatusListener != null) {
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, null);
}
if (ipcConnectionStatus.get() == Constants.IPC_CONNECTION_STATUS.DISCONNECTED ||
ipcConnectionStatus.get() == Constants.IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS) {
switch (adasOptions.getIpcConnectionMode()) {
case AdasOptions.IPC_CONNECTION_MODE.FIXATION:
ipcFixationIPHelper(adasOptions.getIpcFixationIP());
@@ -402,31 +396,31 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
}
@Override
public void onConnecting() {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.CONNECTING;
public void onConnecting(String msg) {
ipcConnectionStatus.set(Constants.IPC_CONNECTION_STATUS.CONNECTING);
if (adasConnectStatusListener != null) {
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, null);
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus.get(), msg);
}
}
@Override
public void onWebSocketConnectSuccess(String ipAddress, int port) {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.CONNECTED;
ipcConnectionStatus.set(Constants.IPC_CONNECTION_STATUS.CONNECTED);
ipcConnectedIp = ipAddress;
ipcConnectedPort = port;
if (adasConnectStatusListener != null) {
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, null);
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus.get(), "已连接");
}
sendCarConfigReq();
}
@Override
public void onWebSocketConnectFailed(String t) {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.DISCONNECTED;
ipcConnectionStatus.set(Constants.IPC_CONNECTION_STATUS.DISCONNECTED);
ipcConnectedIp = null;
ipcConnectedPort = Constants.DEFAULT_PORT;
if (adasConnectStatusListener != null) {
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, t);
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus.get(), t);
}
}
@@ -441,9 +435,9 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
}
private void notFoundAddress() {
ipcConnectionStatus = Constants.IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS;
ipcConnectionStatus.set(Constants.IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS);
if (adasConnectStatusListener != null) {
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus, "地址不可用或不合法");
adasConnectStatusListener.onConnectionIPCStatus(ipcConnectionStatus.get(), "地址不可用或不合法");
}
}
@@ -501,7 +495,7 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
@Override
public int getIpcConnectionStatus() {
return ipcConnectionStatus;
return ipcConnectionStatus.get();
}

View File

@@ -16,9 +16,9 @@ public interface OnAdasConnectStatusListener {
* 与工控机链接状态变化
*
* @param ipcConnectionStatus {@link Constants.IPC_CONNECTION_STATUS}
* @param failedMsg 连接异常信息 需要判null
* 如果ipcConnectionStatus==Constants.IPC_CONNECTION_STATUS.DISCONNECTED&&failedMsg==null 表示主动断开连接
* @param reason 连接信息 需要判null
* 如果ipcConnectionStatus==Constants.IPC_CONNECTION_STATUS.DISCONNECTED&&reason==null 表示主动断开连接
*/
void onConnectionIPCStatus(@Define.IPCConnectionStatus int ipcConnectionStatus, @Nullable String failedMsg);
void onConnectionIPCStatus(@Define.IPCConnectionStatus int ipcConnectionStatus, @Nullable String reason);
}

View File

@@ -8,6 +8,7 @@ import chassis.VehicleStateOuterClass;
import mogo.telematics.pad.MessagePad;
import mogo_msg.MogoReportMsg;
import perception.TrafficLightOuterClass;
import prediction.Prediction;
import record_cache.RecordPanelOuterClass;
/**
@@ -80,6 +81,14 @@ public interface OnAdasListener {
*/
void onPerceptionTrafficLight(MessagePad.Header header, TrafficLightOuterClass.TrafficLights trafficLights);
/**
* 他车轨迹预测
*
* @param header 头
* @param predictionObjects 他车轨迹预测数据
*/
void onPredictionObstacleTrajectory(MessagePad.Header header, Prediction.mPredictionObjects predictionObjects);
/**
* 自动驾驶设备基础信息请求
*

View File

@@ -10,6 +10,8 @@ import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 工控机固定IP查询
@@ -18,8 +20,8 @@ public class IPCFixationIPHelper {
private static final String TAG = IPCFixationIPHelper.class.getSimpleName();
private final IIPCFixationIPListener listener;
private final List<Future> futures = new ArrayList<>();
private volatile boolean isCallListener = false;//是否已经调用了回调
private volatile int unavailableCount = 0;//不可用IP个数
private final AtomicBoolean isCallListener = new AtomicBoolean(false);//是否已经调用了回调
private final AtomicInteger unavailableCount = new AtomicInteger(0);//不可用IP个数
private volatile int queryCount;//要查询的IP个数
private Timer retryTimer;
@@ -48,8 +50,9 @@ public class IPCFixationIPHelper {
void onAvailableIP(String ip);
}
private void interrupted() {
if (!futures.isEmpty()) {
private boolean interrupted() {
boolean isEm = futures.isEmpty();
if (!isEm) {
for (Future future : futures) {
if (!future.isCancelled()) {
future.cancel(true);
@@ -57,6 +60,7 @@ public class IPCFixationIPHelper {
}
futures.clear();
}
return isEm;
}
public void stop() {
@@ -64,9 +68,10 @@ public class IPCFixationIPHelper {
retryTimer.cancel();
retryTimer = null;
}
isCallListener = true;
interrupted();
listener.onStopFindIP();
isCallListener.set(true);
if (!interrupted()) {
listener.onStopFindIP();
}
}
/**
@@ -83,8 +88,8 @@ public class IPCFixationIPHelper {
} else {
interrupted();
queryCount = ips.size();
unavailableCount = 0;
isCallListener = false;
unavailableCount.set(0);
isCallListener.set(false);
for (final String temp : ips) {
Runnable runnable = new Runnable() {
@Override
@@ -92,8 +97,8 @@ public class IPCFixationIPHelper {
CupidLogUtils.i(TAG, "ip=" + temp);
boolean isAvailable = ping(temp);
if (isAvailable) {
if (!isCallListener && !Thread.currentThread().isInterrupted()) {
isCallListener = true;
if (!isCallListener.get() && !Thread.currentThread().isInterrupted()) {
isCallListener.set(true);
listener.onAvailableIP(temp);
CupidLogUtils.i(TAG, "可用IP=" + temp);
interrupted();
@@ -110,10 +115,9 @@ public class IPCFixationIPHelper {
}
private synchronized void allNotAvailable(final HashSet<String> ips) {
unavailableCount++;
if (queryCount == unavailableCount) {
if (!isCallListener) {
isCallListener = true;
if (queryCount == unavailableCount.incrementAndGet()) {
if (!isCallListener.get()) {
isCallListener.set(true);
listener.onAvailableIP(null);
CupidLogUtils.i(TAG, "所有IP均不可用");
//当配置中的所有IP都ping不通时需要继续ping

View File

@@ -19,6 +19,7 @@ public enum MessageType {
TYPE_RECEIVE_AUTOPILOT_STATE(MessagePad.MessageType.MsgTypeAutopilotState, "自动驾驶状态"),
TYPE_RECEIVE_REPORT_MESSAGE(MessagePad.MessageType.MsgTypeReportMessage, "监控事件报告"),
TYPE_RECEIVE_PERCEPTION_TRAFFIC_LIGHT(MessagePad.MessageType.MsgTypePerceptionTrafficLight, "感知红绿灯"),
TYPE_RECEIVE_PREDICTION_OBSTACLE_TRAJECTORY(MessagePad.MessageType.MsgTypePredictionObstacleTrajectory, "他车轨迹预测"),
TYPE_RECEIVE_BASIC_INFO_REQ(MessagePad.MessageType.MsgTypeBasicInfoReq, "自动驾驶设备基础信息请求"),
TYPE_SEND_BASIC_INFO_RESP(MessagePad.MessageType.MsgTypeBasicInfoResp, "自动驾驶设备基础信息应答"),

View File

@@ -2,6 +2,7 @@ package com.zhidao.support.adas.high.common;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 写成单例比较好控制 比如refreshLast()方法可以放到任何接收的回调中,目前放在AutopilotStateMessage 数据接口中,此接口数据刷新不是太频繁
@@ -12,7 +13,7 @@ public class ReceiveTimeoutManager {
private static final String TAG = ReceiveTimeoutManager.class.getSimpleName();
private static volatile ReceiveTimeoutManager INSTANCE;
private static final long DEFAULT_TIMEOUT = 4 * 1000L;//默认超时时间
private volatile boolean isEnable = true;//是否启用超时检测
private final AtomicBoolean isEnable = new AtomicBoolean(true);//是否启用超时检测
private volatile long lastReceiveTime;
private OnTimeoutListener listener;
private volatile Timer timer;
@@ -40,7 +41,7 @@ public class ReceiveTimeoutManager {
}
public boolean isEnable() {
return isEnable;
return isEnable.get();
}
/**
@@ -50,7 +51,7 @@ public class ReceiveTimeoutManager {
* @param ipcConnectionStatus 当前连接状态
*/
public void setEnable(boolean isEnable, @Define.IPCConnectionStatus int ipcConnectionStatus) {
this.isEnable = isEnable;
this.isEnable.set(isEnable);
//如果启动并且当前已连接
if (isEnable) {
if (ipcConnectionStatus == Constants.IPC_CONNECTION_STATUS.CONNECTED)
@@ -65,12 +66,12 @@ public class ReceiveTimeoutManager {
* 刷新最后一次接收数据时间
*/
public void refreshLast() {
if (isEnable)
if (isEnable.get())
lastReceiveTime = System.currentTimeMillis();
}
public synchronized void start() {
if (isEnable)
if (isEnable.get())
if (timer == null) {
refreshLast();
timer = new Timer();

View File

@@ -18,6 +18,7 @@ public class MyMessageFactory implements IMyMessageFactory {
private IMsg autopilotStateMessage;//自动驾驶状态
private IMsg reportMessage;//监控事件报告
private IMsg perceptionTrafficLightMessage;//感知红绿灯
private IMsg predictionObstacleTrajectory;//他车轨迹预测
private IMsg basicInfoReqMessage;//自动驾驶设备基础信息请求
private IMsg carConfigRespMessage;//车机基础信息应答
@@ -91,6 +92,12 @@ public class MyMessageFactory implements IMyMessageFactory {
perceptionTrafficLightMessage = new PerceptionTrafficLightMessage();
}
return perceptionTrafficLightMessage;
} else if (messageType == MessageType.TYPE_RECEIVE_PREDICTION_OBSTACLE_TRAJECTORY.typeCode) {
//他车轨迹预测
if (predictionObstacleTrajectory == null) {
predictionObstacleTrajectory = new PredictionObstacleTrajectoryMessage();
}
return predictionObstacleTrajectory;
} else if (messageType == MessageType.TYPE_RECEIVE_BASIC_INFO_REQ.typeCode) {
//自动驾驶设备基础信息请求
if (basicInfoReqMessage == null) {

View File

@@ -0,0 +1,28 @@
package com.zhidao.support.adas.high.msg;
import com.google.gson.Gson;
import com.google.protobuf.InvalidProtocolBufferException;
import com.zhidao.support.adas.high.OnAdasListener;
import mogo.telematics.pad.MessagePad;
import prediction.Prediction;
/**
* 他车轨迹预测
*/
public class PredictionObstacleTrajectoryMessage extends MyAbstractMessageHandler {
@Override
public void handlerMsg(Gson gson, OnAdasListener adasListener, String msg) {
}
@Override
public void handlerMsg(MessagePad.Header header, byte[] msg, OnAdasListener adasListener) throws InvalidProtocolBufferException {
Prediction.mPredictionObjects objects = Prediction.mPredictionObjects.parseFrom(msg);
if (adasListener != null) {
adasListener.onPredictionObstacleTrajectory(header, objects);
}
}
}

View File

@@ -3,6 +3,8 @@ package com.zhidao.support.adas.high.protocol;
import com.zhidao.support.adas.high.common.Constants;
import com.zhidao.support.adas.high.common.DigitalTrans;
import java.util.concurrent.atomic.AtomicLong;
import mogo.telematics.pad.MessagePad;
import okio.ByteString;
@@ -16,22 +18,21 @@ import okio.ByteString;
public class RawPack {
private static final String TAG = RawPack.class.getSimpleName();
private final DefaultMessageProtocol messageProtocol;
private volatile long msgID = 0L;
private final AtomicLong msgID = new AtomicLong(0L);
public RawPack() {
messageProtocol = new DefaultMessageProtocol();
}
public synchronized ByteString pack(MessagePad.MessageType msgType, byte[] data) {
public synchronized ByteString pack(MessagePad.MessageType msgType, byte[] data) {
if (msgType == null) {
return null;
}
msgID++;
double time = System.nanoTime() / 1000000000.0;
//封装Header
MessagePad.Header.Builder headerBuilder = MessagePad.Header.newBuilder();
headerBuilder.setMsgID(msgID);//消息唯一ID生成数据累加。从1开始程序或者就一直累加,断开连接或者更换连接的工控机不做重置
headerBuilder.setMsgID(msgID.incrementAndGet());//消息唯一ID生成数据累加。从1开始连接未重新初始化就一直累加
headerBuilder.setMsgType(msgType);
headerBuilder.setTimestamp(time);
headerBuilder.setSourceTimestamp(time);

View File

@@ -23,6 +23,7 @@ import com.zhjt.service.chain.TracingConstants;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -62,7 +63,11 @@ public class FpgaSocket implements IWebSocket {
/**
* 是否是用户主动关闭socket
*/
private volatile boolean isUserCloseWebSocket = false;
private final AtomicBoolean isUserClose = new AtomicBoolean(false);
/**
* 是否是被动关闭
*/
private final AtomicBoolean isPassiveClose = new AtomicBoolean(false);
/**
* 是否启用自动重连
*/
@@ -88,8 +93,8 @@ public class FpgaSocket implements IWebSocket {
ReceiveTimeoutManager.getInstance().setListener(new ReceiveTimeoutManager.OnTimeoutListener() {
@Override
public void onTimeout(double time) {
receiveTimeoutReason = "已超过" + time + "未收到工控机数据,将要进行重连";
onClose(receiveTimeoutReason);
receiveTimeoutReason = "心跳超时(" + time + "";
onPassiveClose(receiveTimeoutReason);
}
});
}
@@ -102,17 +107,18 @@ public class FpgaSocket implements IWebSocket {
public void connectWebSocket(String address, int port) {
this.ipAddress = address;
this.port = port;
isUserCloseWebSocket = false;
isUserClose.set(false);
isPassiveClose.set(false);
wsHost = WS_IP_HOST_HEAD + address + String.format(Locale.getDefault(), RESOURCE_PATH, port);
CupidLogUtils.i(TAG, "WebSocket 主动连接= " + wsHost);
init();
connect();
connect("连接中");
}
private void connect() {
private void connect(String msg) {
if (client != null && mWebSocket == null) {
if (mWebSocketConnectListener != null)
mWebSocketConnectListener.onConnecting();
mWebSocketConnectListener.onConnecting(msg);
if (request == null)
request = new Request.Builder()
.url(wsHost)
@@ -126,15 +132,15 @@ public class FpgaSocket implements IWebSocket {
*/
public void reconnect() {
if (isReconnect) {
if (!isUserCloseWebSocket) {
if (!isUserClose.get()) {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
connect();
connect("重连中");
} else {
isUserCloseWebSocket = false;
isUserClose.set(false);
}
}
}
@@ -146,7 +152,8 @@ public class FpgaSocket implements IWebSocket {
WebSocketQueueManager.getInstance().release();
WSByteQueueManager.getInstance().release();
}
isUserCloseWebSocket = true;
isUserClose.set(true);
isPassiveClose.set(false);
if (mWebSocket != null) {
close(true, 1000);
} else {
@@ -187,7 +194,7 @@ public class FpgaSocket implements IWebSocket {
/**
* 正在连接
*/
void onConnecting();
void onConnecting(String msg);
void onWebSocketConnectSuccess(String ipAddress, int port);
@@ -270,31 +277,39 @@ public class FpgaSocket implements IWebSocket {
@Override
public void onClosing(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
super.onClosing(webSocket, code, reason);
CupidLogUtils.e(TAG, "WebSocket onClosing= " + reason);
CupidLogUtils.e(TAG, code + "WebSocket onClosing= " + reason);
String msg = "Code=" + code + " ";
if (TextUtils.isEmpty(reason))
reason = "onClosing";
onClose(reason);
reason = "未知原因";
msg += reason;
onPassiveClose("Closing " + msg);
}
@Override
public void onClosed(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
super.onClosed(webSocket, code, reason);
CupidLogUtils.e(TAG, "WebSocket onClosed= " + reason);
CupidLogUtils.e(TAG, code + "WebSocket onClosed= " + reason);
String msg = "Code=" + code + " ";
if (TextUtils.isEmpty(reason))
reason = "onClosed";
onClose(reason);
reason = "未知原因";
msg += reason;
onPassiveClose("Closed " + msg);
}
@Override
public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, Response response) {
super.onFailure(webSocket, t, response);
CupidLogUtils.e(TAG, "WebSocket onFailure= " + t);
CupidLogUtils.e(TAG, "WebSocket onFailure 是否是被动关闭:" + isPassiveClose + " Throwable=" + t);
if (isPassiveClose.get()) {
isPassiveClose.set(false);
return;
}
String reason = t.toString();
//连接异常或关闭异常不进行堆栈打印
if (!reason.toLowerCase().contains("failed to connect to") && !reason.contains("Socket closed"))
t.printStackTrace();
CupidLogUtils.e(TAG, "WebSocket onFailure", t);
if (TextUtils.isEmpty(reason))
reason = "onFailure";
reason = "未知原因";
if (!TextUtils.isEmpty(receiveTimeoutReason)) {
reason = receiveTimeoutReason;
receiveTimeoutReason = null;
@@ -302,26 +317,33 @@ public class FpgaSocket implements IWebSocket {
if (mWebSocket != null) {
close(false, 1001);
}
onConnectFailed(reason);
onConnectFailed("Failure " + reason);
}
}
private void onConnectFailed(String reason) {
receiveTimeoutReason = null;
ReceiveTimeoutManager.getInstance().stop();
if (mWebSocketConnectListener != null) {
if (isUserCloseWebSocket)
reason = "未连接 " + reason;
if (isUserClose.get())
reason = null;
mWebSocketConnectListener.onWebSocketConnectFailed(reason);
}
reconnect();
}
private void onClose(String reason) {
/**
* 被动关闭 包含:服务断开 心跳超时 异常断开 等
*
* @param reason
*/
private void onPassiveClose(String reason) {
isPassiveClose.set(true);
if (mWebSocket != null) {
close(false, 1001);
} else {
onConnectFailed(reason);
}
onConnectFailed(reason);
}
/**