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

This commit is contained in:
xinfengkun
2022-03-17 17:46:17 +08:00
92 changed files with 2130 additions and 333 deletions

View File

@@ -5,7 +5,7 @@ package com.mogo.och.taxi.passenger.callback;
* @date: 2021/12/3
*/
public interface IOCHTaxiPassengerNaviChangedCallback {
// 当前位置距离上车点的距离(米)、预估时间(秒)
void onCurrentNaviDistAndTimeChanged(int meters, int timeInSecond);
// 当前位置距离上车点的距离(米)、预估时间(秒) 、当前路的名称
void onCurrentNaviDistAndTimeChanged(int meters, int timeInSecond, String currentRoadName);
void reInitNaviAmap(boolean isPlay,boolean isRestart);
}

View File

@@ -17,6 +17,6 @@ public interface IOCHTaxiPassengerOrderStatusCallback {
void onCurrentOrderStatusChanged(TaxiPassengerOrderQueryRespBean.Result order);
// 当前位置距离上车点的距离(米)、预估时间(秒)
void onCurrentOrderDistToEndChanged(int meters, int timeInSecond);
void onCurrentOrderDistToEndChanged(int meters, int timeInSecond, String currentRoadName);
}

View File

@@ -37,5 +37,8 @@ class TaxiPassengerConst {
// 订单信息
const val SP_KEY_OCH_TAXI_ORDER = "SP_KEY_OCH_TAXI_ORDER"
// 订单总里程
const val SP_KEY_ORDER_SUM_DIS = "SP_KEY_ORDER_SUM_DIS"
}
}

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.net.ConnectivityManager;
import android.os.Looper;
import androidx.annotation.Nullable;
@@ -11,9 +12,8 @@ import com.amap.api.navi.model.NaviLatLng;
import com.elegant.network.utils.GsonUtil;
import com.mogo.cloud.commons.utils.CoordinateUtils;
import com.mogo.commons.debug.DebugConfig;
import com.mogo.commons.voice.AIAssist;
import com.mogo.eagle.core.data.autopilot.ADASTrajectoryInfo;
import com.mogo.eagle.core.data.autopilot.AutopilotGuardianStatusInfo;
import com.mogo.eagle.core.data.autopilot.AutopilotStationInfo;
import com.mogo.eagle.core.data.autopilot.AutopilotStatusInfo;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.data.map.MogoLocation;
@@ -27,8 +27,10 @@ import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
import com.mogo.eagle.core.utilcode.util.NetworkUtils;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.map.navi.IMogoCarLocationChangedListener2;
import com.mogo.module.common.MogoApisHandler;
import com.mogo.och.taxi.passenger.R;
import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRespBean;
import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrdersInServiceQueryRespBean;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerADASStatusCallback;
@@ -81,6 +83,12 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback
private volatile List<TaxiPassengerOrderQueryRespBean.Result> mInServiceList = Collections.emptyList(); //进行中订单
private volatile List<TaxiPassengerOrderQueryRespBean.Result> mWaitServiceList = Collections.emptyList(); //待服务订单
public void setmTtsLessThan200Tip(int ttsLessThan200Tip) {
this.mTtsLessThan200Tip = ttsLessThan200Tip;
}
private volatile int mTtsLessThan200Tip = 0;//离终点200米提示播报
private IOCHTaxiPassengerADASStatusCallback mADASStatusCallback; //Model->Presenter自动驾驶状态相关
private IOCHTaxiPassengerAutopilotPlanningCallback mAutopilotPlanningCallback; //Model->Presenter自动驾驶线路规划
@@ -310,22 +318,6 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback
});
}
// 车机端上传心跳数据(只在出车状态时上传)
// public void runCarHeartbeat() {
// TaxiPassengerServiceManager.getInstance().runCarHeartbeat(mContext, mLongitude, mLatitude,
// new TaxiPassengerServiceCallback<BaseData>() {
// @Override
// public void onSuccess(BaseData data) {
//
// }
//
// @Override
// public void onFail(int code, String msg) {
//
// }
// });
// }
// 获取当前订单
public TaxiPassengerOrderQueryRespBean.Result getCurrentOCHOrder() {
return mCurrentOCHOrder;
@@ -578,25 +570,51 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback
};
/**
*
* 导航订单起点到终点 获得剩余时间,里程,预计到达时间
*/
public void naviOrderStartToEnd() {
NaviLatLng startNaviLatLng = new NaviLatLng(mLongitude,mLatitude);
NaviLatLng endNaviLatLng = new NaviLatLng(mCurrentOCHOrder.endSiteGcjPoint.get(1), mCurrentOCHOrder.endSiteGcjPoint.get(0));
TaxiPassengerNaviToDestinationModel.getInstance(mContext).initAMapNavi(startNaviLatLng, endNaviLatLng);
TaxiPassengerNaviToDestinationModel.getInstance(mContext).setOCHTaciNaviChangedCallback(this);
TaxiPassengerNaviToDestinationModel.getInstance(mContext).destroyAmaNavi();
if (mCurrentOCHOrder != null){
NaviLatLng startNaviLatLng = new NaviLatLng(mLatitude,mLongitude);
NaviLatLng endNaviLatLng = new NaviLatLng(mCurrentOCHOrder.endSiteGcjPoint.get(1),mCurrentOCHOrder.endSiteGcjPoint.get(0));
TaxiPassengerNaviToDestinationModel.getInstance(mContext).initAMapNavi(startNaviLatLng, endNaviLatLng);
TaxiPassengerNaviToDestinationModel.getInstance(mContext).setOCHTaciNaviChangedCallback(this);
}
// else {
// NaviLatLng startNaviLatLng = new NaviLatLng(40.200478,116.741377);
// NaviLatLng endNaviLatLng = new NaviLatLng(40.200863,116.732574);
// TaxiPassengerNaviToDestinationModel.getInstance(mContext).initAMapNavi(startNaviLatLng, endNaviLatLng);
// TaxiPassengerNaviToDestinationModel.getInstance(mContext).setOCHTaciNaviChangedCallback(this);
// }
}
@Override
public void onCurrentNaviDistAndTimeChanged(int meters, int timeInSecond) {
public void onCurrentNaviDistAndTimeChanged(int meters, int timeInSecond, String currentRoadName) {
if (mTtsLessThan200Tip == 0 && meters <= 200){
mTtsLessThan200Tip = 1;
runOnUIThread(() -> {
AIAssist.getInstance(mContext).speakTTSVoice(mContext.getString(R.string.taxi_p_arrive_end_tts_200));
});
}
for (IOCHTaxiPassengerOrderStatusCallback callback :mOrderStatusCallbackMap.values()){
callback.onCurrentOrderDistToEndChanged(meters,timeInSecond);
callback.onCurrentOrderDistToEndChanged(meters,timeInSecond,currentRoadName);
}
}
@Override
public void reInitNaviAmap(boolean isPlay, boolean isRestart) {
naviOrderStartToEnd();
}
private void runOnUIThread(Runnable executor) {
if (executor == null) {
return;
}
if (Looper.myLooper() != Looper.getMainLooper()) {
UiThreadHandler.post(executor);
} else {
executor.run();
}
}
}

View File

@@ -2,7 +2,6 @@ package com.mogo.och.taxi.passenger.model;
import android.Manifest;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.amap.api.navi.AMapNavi;
@@ -23,9 +22,11 @@ import com.amap.api.navi.model.AimLessModeStat;
import com.amap.api.navi.model.NaviInfo;
import com.amap.api.navi.model.NaviLatLng;
import com.autonavi.tbt.TrafficFacilityInfo;
import com.mogo.eagle.core.utilcode.mogo.toast.TipToast;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
import com.mogo.eagle.core.utilcode.util.NetworkUtils;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerNaviChangedCallback;
import com.mogo.och.taxi.passenger.constant.TaxiPassengerConst;
import com.mogo.och.taxi.passenger.utils.PermissionUtil;
import java.util.ArrayList;
@@ -37,6 +38,9 @@ import java.util.concurrent.atomic.AtomicInteger;
* @date: 2021/12/6
*/
public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
private final String TAG = TaxiPassengerNaviToDestinationModel.class.getSimpleName();
private static Context mContext;
private AMapNavi mAMapNavi = null;
protected final List<NaviLatLng> sList = new ArrayList<NaviLatLng>();
@@ -45,6 +49,13 @@ public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
private IOCHTaxiPassengerNaviChangedCallback mNaviChangedCallback;
private AtomicInteger errorCount = new AtomicInteger(0);
private boolean isPlay;
private volatile int mFirstcalculateDriveRoute = 0;
public void setFirstcalculateDriveRoute(int firstcalculateDriveRoute) {
this.mFirstcalculateDriveRoute = firstcalculateDriveRoute;
}
public static TaxiPassengerNaviToDestinationModel getInstance(Context context) {
mContext = context;
return SingletonHolder.INSTANCE;
@@ -63,6 +74,14 @@ public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
mAMapNavi.stopSpeak();
sList.add(startLatLng);
eList.add(endLatLng);
int strategy = 0;
try {
//再次强调最后一个参数为true时代表多路径否则代表单路径
strategy = mAMapNavi.strategyConvert(true, false, false, false, false);
} catch (Exception e) {
e.printStackTrace();
}
mAMapNavi.calculateDriveRoute(sList, eList, mWayPointList, strategy);
}catch (Exception e) {
e.printStackTrace();
}
@@ -84,6 +103,8 @@ public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
mAMapNavi.destroy();
mAMapNavi = null;
mNaviChangedCallback = null;
sList.clear();
eList.clear();
}
}
@@ -98,38 +119,27 @@ public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
@Override
public void onInitNaviSuccess() {
//初始化成功
/**
* 方法: int strategy=mAMapNavi.strategyConvert(congestion, avoidhightspeed, cost, hightspeed, multipleroute); 参数:
*
* @congestion 躲避拥堵
* @avoidhightspeed 不走高速
* @cost 避免收费
* @hightspeed 高速优先
* @multipleroute 多路径
*
* 说明: 以上参数都是boolean类型其中multipleroute参数表示是否多条路线如果为true则此策略会算出多条路线。
* 注意: 不走高速与高速优先不能同时为true 高速优先与避免收费不能同时为true
*/
int strategy = 0;
try {
//再次强调最后一个参数为true时代表多路径否则代表单路径
strategy = mAMapNavi.strategyConvert(true, false, false, false, false);
} catch (Exception e) {
e.printStackTrace();
}
mAMapNavi.calculateDriveRoute(sList, eList, mWayPointList, strategy);
}
@Override
public void onCalculateRouteSuccess(int[] ints) {
//多路径算路成功回调
Logger.d(TAG,"onCalculateRouteSuccess");
mAMapNavi.startNavi(NaviType.GPS);
}
@Override
public void onNaviInfoUpdate(NaviInfo naviinfo) {
//导航过程中的信息更新请看NaviInfo的具体说明
Logger.d(TAG,"naviinfo = "+naviinfo.getPathRetainDistance()+" ,"+naviinfo.getPathRetainTime()
+" ,"+naviinfo.getCurrentRoadName());
if (mFirstcalculateDriveRoute == 0 && SharedPrefsMgr.getInstance(mContext).getInt(TaxiPassengerConst.SP_KEY_ORDER_SUM_DIS,0) == 0){
mFirstcalculateDriveRoute = 1;
SharedPrefsMgr.getInstance(mContext).putInt(TaxiPassengerConst.SP_KEY_ORDER_SUM_DIS,naviinfo.getPathRetainDistance());
}
if (null != mNaviChangedCallback){
mNaviChangedCallback.onCurrentNaviDistAndTimeChanged(naviinfo.getPathRetainDistance(),naviinfo.getPathRetainTime());// 米、秒
mNaviChangedCallback.onCurrentNaviDistAndTimeChanged(naviinfo.getPathRetainDistance()
,naviinfo.getPathRetainTime(),naviinfo.getCurrentRoadName());// 米、秒
}
}
@@ -149,14 +159,12 @@ public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
}
}
if (!NetworkUtils.isConnected(mContext) || result.getErrorCode() == 2){
TipToast.longTip("网络异常,请重试");
if (mNaviChangedCallback != null){
mNaviChangedCallback.reInitNaviAmap(isPlay,false);
}
return;
}
if (!PermissionUtil.isLocServiceEnable(mContext) || !PermissionUtil.checkPermission(mContext,new String[]{Manifest.permission.ACCESS_FINE_LOCATION})){
TipToast.longTip("请开启车机定位后重试");
if (mNaviChangedCallback != null){
mNaviChangedCallback.reInitNaviAmap(isPlay,false);
}
@@ -167,8 +175,8 @@ public class TaxiPassengerNaviToDestinationModel implements AMapNaviListener {
// }else if (result.getErrorCode() == 6){
// TipToast.longTip("终点坐标错误");
// }
Log.i("dm", "路线计算失败:错误码=" + result.getErrorCode() + ",Error Message= " + result.getErrorDetail());
Log.i("dm", "错误码详细链接见http://lbs.amap.com/api/android-navi-sdk/guide/tools/errorcode/");
Logger.i(TAG, "路线计算失败:错误码=" + result.getErrorCode() + ",Error Message= " + result.getErrorDetail());
Logger.i(TAG, "错误码详细链接见http://lbs.amap.com/api/android-navi-sdk/guide/tools/errorcode/");
}
@Override
public void onStartNavi(int type) {

View File

@@ -9,15 +9,20 @@ import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.mvp.Presenter;
import com.mogo.commons.voice.AIAssist;
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.taxi.passenger.R;
import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRespBean;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerADASStatusCallback;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerControllerStatusCallback;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerOrderStatusCallback;
import com.mogo.och.taxi.passenger.constant.TaxiPassengerConst;
import com.mogo.och.taxi.passenger.constant.TaxiPassengerOrderStatusEnum;
import com.mogo.och.taxi.passenger.model.TaxiPassengerModel;
import com.mogo.och.taxi.passenger.model.TaxiPassengerNaviToDestinationModel;
import com.mogo.och.taxi.passenger.ui.TaxiPassengerBaseFragment;
/**
@@ -118,26 +123,49 @@ public class BaseTaxiPassengerPresenter extends Presenter<TaxiPassengerBaseFragm
Log.d(TAG,"order = "+order.toString());
if (mCurrentPassengerOrder == null){
mCurrentPassengerOrder = order; //当前无订单
updateOrderView(mCurrentPassengerOrder);
updateOrderView(order);
}else if (mCurrentPassengerOrder.orderStatus != order.orderStatus) {
mCurrentPassengerOrder = order;
updateOrderView(order);
}
}
@Override
public void onCurrentOrderDistToEndChanged(int meters, int timeInSecond, String currentRoadName) {
}
private void updateOrderView(TaxiPassengerOrderQueryRespBean.Result order) {
if (TaxiPassengerOrderStatusEnum.Cancel.getCode() == order.orderStatus){
mView.showOrHideServingOrderFragment(false);
recoverNaviInfo();
return;
}
if (TaxiPassengerOrderStatusEnum.ArriveAtStartStation.getCode() == order.orderStatus
|| TaxiPassengerOrderStatusEnum.OnTheWayToEndStation.getCode() == order.orderStatus){
mView.showOrHideServingOrderFragment(true);
return;
}
if (TaxiPassengerOrderStatusEnum.ArriveAtEndStation.getCode() == order.orderStatus){
recoverNaviInfo();
runOnUIThread(() ->{
AIAssist.getInstance(getContext()).speakTTSVoice(getContext().getString(R.string.taxi_p_arrive_end_tts));
});
mView.showOrHideServingOrderFragment(false);
mView.showOrHideArrivedEndLayout(true,order.endSiteAddr);
return;
}
if (TaxiPassengerOrderStatusEnum.JourneyCompleted.getCode() == order.orderStatus){
mView.showOrHideArrivedEndLayout(false,"");
return;
}
}
@Override
public void onCurrentOrderDistToEndChanged(int meters, int timeInSecond) {
/**
* 订单结束或者取消的时候, 刷新导航标识位以及缓存的数据
*/
public void recoverNaviInfo(){
SharedPrefsMgr.getInstance(getContext()).remove(TaxiPassengerConst.SP_KEY_ORDER_SUM_DIS);
TaxiPassengerNaviToDestinationModel.getInstance(getContext()).setFirstcalculateDriveRoute(0);
}
}

View File

@@ -8,16 +8,21 @@ import androidx.annotation.RequiresApi;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.mvp.Presenter;
import com.mogo.commons.voice.AIAssist;
import com.mogo.eagle.core.data.map.MogoLatLng;
import com.mogo.och.taxi.passenger.R;
import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRespBean;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerAutopilotPlanningCallback;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerControllerStatusCallback;
import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerOrderStatusCallback;
import com.mogo.och.taxi.passenger.callback.ITaxiPassengerVeloctityCallback;
import com.mogo.och.taxi.passenger.constant.TaxiPassengerOrderStatusEnum;
import com.mogo.och.taxi.passenger.model.TaxiPassengerModel;
import com.mogo.och.taxi.passenger.ui.TaxiPassengerServingOrderFragment;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import mogo.telematics.pad.MessagePad;
@@ -76,13 +81,18 @@ public class TaxiPassengerServingOrderPresenter extends Presenter<TaxiPassengerS
mView.updateOrderStatusView(order);
}else if (mCurrentPassengerOrder.orderStatus != order.orderStatus) {
mView.updateOrderStatusView(order);
if (TaxiPassengerOrderStatusEnum.Cancel.getCode() == mCurrentPassengerOrder.orderStatus
|| TaxiPassengerOrderStatusEnum.ArriveAtStartStation.getCode() == mCurrentPassengerOrder.orderStatus){
TaxiPassengerModel.getInstance().setmTtsLessThan200Tip(0);
}
mCurrentPassengerOrder = order;
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onCurrentOrderDistToEndChanged(int meters, int timeInSecond) {
mView.onCurrentOrderDistToEndChanged(meters,timeInSecond);
public void onCurrentOrderDistToEndChanged(int meters, int timeInSecond, String currentRoadName) {
mView.onCurrentOrderDistToEndChanged(meters, timeInSecond, currentRoadName);
}
@Override

View File

@@ -5,8 +5,10 @@ import android.os.Looper;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.FragmentTransaction;
import com.mogo.commons.AbsMogoApplication;
@@ -43,6 +45,9 @@ public class TaxiPassengerBaseFragment extends MvpFragment<TaxiPassengerBaseFrag
private TaxiPassengerTrafficLightView mTrafficLightView;
private TaxiPassengerV2XNotificationView mV2XNotificationView;
private ConstraintLayout mArrivedEndCL;
private TextView mArrivedEndStation;
protected TaxiPassengerServingOrderFragment ochServingOrderFragment = null;
private Handler mHandler = new Handler(Looper.getMainLooper());
@@ -70,6 +75,9 @@ public class TaxiPassengerBaseFragment extends MvpFragment<TaxiPassengerBaseFrag
mV2XNotificationView = new TaxiPassengerV2XNotificationView(getContext());
CallerHmiManager.INSTANCE.setProxyNotificationView(mV2XNotificationView);
mArrivedEndCL = findViewById(R.id.taxi_p_arrive_end_bg);
mArrivedEndStation = findViewById(R.id.arrived_end_station);
mMapswitchBtn = findViewById(R.id.module_och_taxi_swich_map_iv);
mMapswitchBtn.setOnClickListener(new View.OnClickListener() {
@Override
@@ -100,7 +108,7 @@ public class TaxiPassengerBaseFragment extends MvpFragment<TaxiPassengerBaseFrag
*/
private void hideEagleConfig() {
//隐藏小地图
CallerSmpManager.hidePanel();
CallerSmpManager.INSTANCE.hidePanel();
}
@Override
@@ -220,4 +228,17 @@ public class TaxiPassengerBaseFragment extends MvpFragment<TaxiPassengerBaseFrag
}
transaction.commitAllowingStateLoss();
}
/**
* 显示或者隐藏到达乘客站点的洁面
* @param isShow
*/
public void showOrHideArrivedEndLayout(boolean isShow, String arrivedEndStation){
if (isShow){
mArrivedEndCL.setVisibility(View.VISIBLE);
mArrivedEndStation.setText(arrivedEndStation);
}else {
mArrivedEndCL.setVisibility(View.GONE);
}
}
}

View File

@@ -17,19 +17,24 @@ import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.mogo.commons.mvp.MvpFragment;
import com.mogo.eagle.core.data.autopilot.AutopilotRouteInfo;
import com.mogo.eagle.core.data.map.MogoLatLng;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.taxi.passenger.R;
import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRespBean;
import com.mogo.och.taxi.passenger.callback.ITaxiPassengerMapViewCallback;
import com.mogo.och.taxi.passenger.constant.TaxiPassengerConst;
import com.mogo.och.taxi.passenger.constant.TaxiPassengerOrderStatusEnum;
import com.mogo.och.taxi.passenger.model.TaxiPassengerModel;
import com.mogo.och.taxi.passenger.model.TaxiPassengerNaviToDestinationModel;
import com.mogo.och.taxi.passenger.presenter.TaxiPassengerServingOrderPresenter;
import com.mogo.och.taxi.passenger.utils.TaxiPassengerUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
@@ -62,8 +67,11 @@ public class TaxiPassengerServingOrderFragment extends
private RotateAnimation rotateAnimation;
private SeekBar mProgressSeekBar;
private TextView mProgessDes;
private int mLimitingVelocity;// 返回的道路限速值
private TaxiPassengerCardView mSpeedLayoutBg;
private int mLimitingVelocity = 0;// 返回的道路限速值
public static TaxiPassengerServingOrderFragment newInstance() {
@@ -99,23 +107,203 @@ public class TaxiPassengerServingOrderFragment extends
mMapArrowIcon = findViewById(R.id.taxi_p_arrow_nor);
mProgressSeekBar = findViewById(R.id.taxi_p_seekbar);
mProgessDes = findViewById(R.id.taxi_p_progress_des);
mSpeedLayoutBg = findViewById(R.id.taxi_p_speed_bg);
mTPOrderStatus.setOnLongClickListener(new View.OnLongClickListener() { //测试用
@Override
public boolean onLongClick(View v) {
String listStr = "{\"models\":[{\n" +
"\t\t\"lat\": 40.19927810144466,\n" +
"\t\t\"lon\": 116.73527259387767\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19927836356079,\n" +
"\t\t\"lon\": 116.73513114732762\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19927759500293,\n" +
"\t\t\"lon\": 116.73497660879111\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.199264819842284,\n" +
"\t\t\"lon\": 116.73480063747202\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1992510141554,\n" +
"\t\t\"lon\": 116.73463922037767\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.199245872804,\n" +
"\t\t\"lon\": 116.73445960685193\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924673374912,\n" +
"\t\t\"lon\": 116.73427704009703\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924747108264,\n" +
"\t\t\"lon\": 116.7340707102972\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924828745573,\n" +
"\t\t\"lon\": 116.73385916927226\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924941093133,\n" +
"\t\t\"lon\": 116.73364048294795\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924939253381,\n" +
"\t\t\"lon\": 116.73340837408566\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924949105934,\n" +
"\t\t\"lon\": 116.73317368725336\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19925040039033,\n" +
"\t\t\"lon\": 116.73296532811216\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1992515355653,\n" +
"\t\t\"lon\": 116.73277787366743\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1992512720328,\n" +
"\t\t\"lon\": 116.73263377253741\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.199205174954606,\n" +
"\t\t\"lon\": 116.73249773114644\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1991015743076,\n" +
"\t\t\"lon\": 116.7324219601283\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.198971862686285,\n" +
"\t\t\"lon\": 116.73239393296355\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19883883071582,\n" +
"\t\t\"lon\": 116.73237676435652\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19870171355796,\n" +
"\t\t\"lon\": 116.73236052150362\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1985491853193,\n" +
"\t\t\"lon\": 116.73234157857011\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1983890047355,\n" +
"\t\t\"lon\": 116.73232167996464\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1982209877466,\n" +
"\t\t\"lon\": 116.73230101645792\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.198037574138326,\n" +
"\t\t\"lon\": 116.73227735486083\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19787327856243,\n" +
"\t\t\"lon\": 116.73225676816314\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19771917207499,\n" +
"\t\t\"lon\": 116.73223814728027\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197548305175935,\n" +
"\t\t\"lon\": 116.73221624705808\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19739568979691,\n" +
"\t\t\"lon\": 116.73219618210774\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19724703821575,\n" +
"\t\t\"lon\": 116.73217598293311\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1970956560885,\n" +
"\t\t\"lon\": 116.73215773721505\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19697703483188,\n" +
"\t\t\"lon\": 116.73214337172284\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19687000725696,\n" +
"\t\t\"lon\": 116.73210037067965\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.196833449601726,\n" +
"\t\t\"lon\": 116.73196646708011\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19685833847804,\n" +
"\t\t\"lon\": 116.73181315361103\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.196889170203264,\n" +
"\t\t\"lon\": 116.73164355747393\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19692242860347,\n" +
"\t\t\"lon\": 116.7314555399657\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19696431701069,\n" +
"\t\t\"lon\": 116.7312261834129\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19700025925464,\n" +
"\t\t\"lon\": 116.73102774016093\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19703414798773,\n" +
"\t\t\"lon\": 116.73084270562073\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19707287604138,\n" +
"\t\t\"lon\": 116.73062835248406\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19710951629977,\n" +
"\t\t\"lon\": 116.73041744082339\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19714593807105,\n" +
"\t\t\"lon\": 116.73021414314803\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197183297026285,\n" +
"\t\t\"lon\": 116.7300057066447\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1972247359487,\n" +
"\t\t\"lon\": 116.7297751515664\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19726518822745,\n" +
"\t\t\"lon\": 116.72954958923812\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19730538240706,\n" +
"\t\t\"lon\": 116.72932440756041\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19734272112662,\n" +
"\t\t\"lon\": 116.72911631453036\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197379191549075,\n" +
"\t\t\"lon\": 116.72890982812105\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197417565369314,\n" +
"\t\t\"lon\": 116.72869447869044\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19746052080799,\n" +
"\t\t\"lon\": 116.72845641541247\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19750040582118,\n" +
"\t\t\"lon\": 116.72823569991117\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19753999704064,\n" +
"\t\t\"lon\": 116.72801998373052\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19757796882569,\n" +
"\t\t\"lon\": 116.72781280504363\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197617062364586,\n" +
"\t\t\"lon\": 116.72759949431683\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19765391602761,\n" +
"\t\t\"lon\": 116.72739776789756\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19768973009218,\n" +
"\t\t\"lon\": 116.72719980764646\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197726191028785,\n" +
"\t\t\"lon\": 116.72699719861669\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19776233489642,\n" +
"\t\t\"lon\": 116.72679516155276\n" +
"\t}]}\n";
List<MessagePad.Location> list = new ArrayList<>();
for (int i = 0; i < 200; i++) {
MessagePad.Location.Builder builder = MessagePad.Location.newBuilder();
AutopilotRouteInfo.RouteModels routeModels = new AutopilotRouteInfo.RouteModels();
if (i <= 100) {
builder.setLatitude(40.199248903658166);
builder.setLongitude(116.73435586102245 + i * 0.0001);
} else {
builder.setLatitude(40.199248903658166 + i * 0.0001);
builder.setLongitude(116.73435586102245 + 100 * 0.0001);
try {
JSONObject jsonObject = new JSONObject(listStr);
JSONArray jsonElements = jsonObject.getJSONArray("models");
for (int i = 0; i < jsonElements.length(); i++){
JSONObject s = jsonElements.getJSONObject(i);
MessagePad.Location.Builder routeModels = MessagePad.Location.newBuilder();
routeModels.setLatitude(s.getDouble("lat"));
routeModels.setLongitude(s.getDouble("lon"));
list.add(routeModels.build());
}
list.add(builder.build());
} catch (JSONException e) {
e.printStackTrace();
}
mPresenter.routeResult(list);
return true;
}
@@ -142,7 +330,7 @@ public class TaxiPassengerServingOrderFragment extends
*/
private void setSeekBarMax() {
//计算订单起点和终点距离
int maxInt = TaxiPassengerModel.getInstance().calculateOrderDistanceSum();
int maxInt = SharedPrefsMgr.getInstance(getContext()).getInt(TaxiPassengerConst.SP_KEY_ORDER_SUM_DIS,0);
Logger.d(TAG, "maxInt = " + maxInt);
mProgressSeekBar.setMax(maxInt);
}
@@ -151,9 +339,10 @@ public class TaxiPassengerServingOrderFragment extends
* 行驶进度值更新
*/
@RequiresApi(api = Build.VERSION_CODES.N)
private void updateDriveProcessLoading(int progressLoading) {
private void updateDriveProcessLoading(int progressLoading,String currentRoadName) {
mProgessDes.setText(currentRoadName);
mProgressSeekBar.setProgress(
TaxiPassengerModel.getInstance().calculateOrderDistanceSum() - progressLoading
SharedPrefsMgr.getInstance(getContext()).getInt(TaxiPassengerConst.SP_KEY_ORDER_SUM_DIS,0) - progressLoading
, true);
}
@@ -234,24 +423,32 @@ public class TaxiPassengerServingOrderFragment extends
if (TaxiPassengerOrderStatusEnum.OnTheWayToEndStation.getCode() == order.orderStatus) {
mTPOrderStatus.setText(R.string.taxi_p_start_to_end);
setSeekBarMax();
return;
}
}
/**
* 剩余里程,剩余时间,当前定位点所在道路
* @param meters
* @param timeInSecond
* @param currentRoadName
*/
@RequiresApi(api = Build.VERSION_CODES.N)
public void onCurrentOrderDistToEndChanged(int meters, int timeInSecond) {
Calendar calendarArrive = TaxiPassengerUtils.formatLongToCalendar(System.currentTimeMillis() + timeInSecond);
String arriveTime = TaxiPassengerUtils.formatCalendarToString(calendarArrive, TaxiPassengerUtils.TAXI_HH_mm);
public void onCurrentOrderDistToEndChanged(int meters, int timeInSecond, String currentRoadName) {
DecimalFormat fnum = new DecimalFormat("##0.00");
String remainDis = fnum.format((float) meters / 1000);
int remainTime = (int) timeInSecond / 60;
Calendar beforeTime = Calendar.getInstance();
beforeTime.add(Calendar.MINUTE,remainTime);
String arriveTime = TaxiPassengerUtils.formatCalendarToString(beforeTime,TaxiPassengerUtils.TAXI_HH_mm);
updateOrderDisAndTimeView(remainDis, remainTime, arriveTime);
updateDriveProcessLoading(meters);
updateDriveProcessLoading(meters,currentRoadName);
}
private void updateOrderDisAndTimeView(String remainDis, int remainTime, String arriveTime) {
mTPOrderRemainDis.setText(remainDis);
mTPOrderRemainTime.setText(remainTime);
mTPOrderRemainTime.setText(String.valueOf(remainTime));
mTPOrderRemainArriveTime.setText(arriveTime);
}
@@ -270,10 +467,13 @@ public class TaxiPassengerServingOrderFragment extends
*/
private void updateSpeedView(float newSpeed) {
int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值
Logger.d(TAG,"mLimitingVelocity = "+mLimitingVelocity);
if (speed < mLimitingVelocity) {
mTPSpeedTv.setText(getSpeedTextStyle(String.valueOf(speed), true));
mSpeedLayoutBg.setBackgroundResource(R.drawable.taxi_p_speed_light_green_bg);
} else {
mTPSpeedTv.setText(getSpeedTextStyle(String.valueOf(speed), false));
mSpeedLayoutBg.setBackgroundResource(R.drawable.taxi_p_speed_light_red_bg);
}
}
@@ -288,6 +488,7 @@ public class TaxiPassengerServingOrderFragment extends
if (isNormal) {
return TaxiPassengerUtils.getGradientFontSpan(content
, 0xFFCEEEFF, 0xFFA1DAFF);
} else {//超速
return TaxiPassengerUtils.getGradientFontSpan(content
, 0xFFFE2505, 0xFFFF6F62);

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:bottomRightRadius="40px"
android:bottomLeftRadius="40px"/>
<gradient
android:startColor="#26263A5B"
android:endColor="#80263A5B"/>
</shape>

View File

@@ -1,28 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 背景图 -->
<item android:id="@android:id/background">
<shape>
<corners android:radius="20dp"/>
<solid android:color="#576F6F6F" />
<solid android:color="#00e2e2e2" />
</shape>
</item>
<!-- 第二进度条的背景色 -->
<!--<item android:id="@android:id/secondaryProgress">
<clip>
<shape android:shape="rectangle" >
<solid android:color="#98E3D9" />
</shape>
</clip>
</item>-->
<!-- <item android:id="@+android:id/background" android:drawable="@drawable/bar_dn" /> -->
<!-- 可拖动的进度条颜色 -->
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="20dp"/>
<solid android:color="#FC82B7F6" />
<solid android:color="#84D4FF" /> <!-- #3FA5FF #84D4FF 渐变-->
</shape>
</clip>
</item>

View File

@@ -8,11 +8,22 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="@dimen/taxi_p_order_panel_width"
android:layout_height="@dimen/taxi_p_order_panel_height"
android:layout_marginTop="@dimen/dp_72"
android:layout_marginTop="@dimen/dp_55"
android:background="@drawable/taxi_passenger_order_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.mogo.och.taxi.passenger.ui.TaxiPassengerCardView
android:id="@+id/taxi_p_speed_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:taxi_right_top_radius="@dimen/dp_40"
app:taxi_left_top_radius="@dimen/dp_40"
android:background="@drawable/taxi_p_speed_light_green_bg"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/taxi_p_order_stations"
android:layout_width="match_parent"
@@ -116,6 +127,7 @@
android:layout_height="wrap_content"
android:text="0"
android:textColor="#84D4FF"
android:includeFontPadding="false"
android:textSize="42px"
android:textStyle="bold" />
@@ -128,6 +140,7 @@
android:layout_toRightOf="@+id/taxi_p_order_remain_distance"
android:text="KM"
android:textColor="#FFFFFF"
android:includeFontPadding="false"
android:textSize="20px" />
</LinearLayout>
@@ -139,6 +152,7 @@
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_10"
android:text="距离"
android:includeFontPadding="false"
android:textColor="#8FB3EF"
android:textSize="20px" />
@@ -165,6 +179,7 @@
android:layout_height="wrap_content"
android:text="0"
android:textColor="#84D4FF"
android:includeFontPadding="false"
android:textSize="42px"
android:textStyle="bold" />
@@ -177,6 +192,7 @@
android:layout_toRightOf="@+id/taxi_p_order_remain_time"
android:text="分钟"
android:textColor="#FFFFFF"
android:includeFontPadding="false"
android:textSize="20px" />
</LinearLayout>
@@ -188,6 +204,7 @@
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_10"
android:text="剩余"
android:includeFontPadding="false"
android:textColor="#8FB3EF"
android:textSize="20px" />
@@ -207,6 +224,7 @@
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="0"
android:includeFontPadding="false"
android:textColor="#84D4FF"
android:textSize="42px"
android:textStyle="bold" />
@@ -219,6 +237,7 @@
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_10"
android:text="到达"
android:includeFontPadding="false"
android:textColor="#8FB3EF"
android:textSize="20px" />
@@ -235,25 +254,43 @@
<SeekBar
android:id="@+id/taxi_p_seekbar"
android:layout_width="248px"
android:layout_height="6px"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:thumbOffset="0dp"
android:focusable="true"
style="@style/CustomSeekbarStyle"
android:layout_marginBottom="36px"
android:layout_marginLeft="34px"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:thumb="@drawable/taxi_p_arrow_nor"/>
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/taxi_p_progress_des"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/taxi_p_seekbar"
app:layout_constraintBottom_toTopOf="@+id/taxi_p_seekbar"
android:textColor="@android:color/white"
android:textSize="@dimen/taxi_p_progress_des_size"
android:textStyle="italic"
android:typeface="monospace"
android:layout_marginBottom="@dimen/dp_15"/>
<ImageView
android:id="@+id/taxi_p_arrow_nor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="44px"
android:layout_marginBottom="30px"
android:layout_marginRight="@dimen/dp_44"
android:layout_marginBottom="@dimen/dp_10"
android:src="@drawable/taxi_p_arrow_nor"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_124"
app:layout_constraintBottom_toBottomOf="parent"
android:background="@drawable/taxi_p_map_bottom_shape"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
@@ -269,12 +306,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_28"
android:shadowColor="#D1193D66"
android:shadowColor="@color/taxi_p_speed_color"
android:shadowDx="0"
android:shadowDy="1"
android:shadowRadius="1"
android:includeFontPadding="false"
android:text="0"
android:textSize="120px"
android:textSize="@dimen/taxi_p_speed_size"
android:textStyle="bold"/>
<TextView
@@ -283,6 +321,7 @@
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:text="KM/h"
android:includeFontPadding="false"
android:textColor="@android:color/white"
android:textSize="26px" />

View File

@@ -113,4 +113,55 @@
android:layout_marginRight="@dimen/taxi_p_traffic_light_layout_margin_right"
android:layout_marginTop="@dimen/taxi_p_traffic_light_layout_margin_top"
android:visibility="gone"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/taxi_p_arrive_end_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/taxi_p_arrive_end_panel_bg"
android:visibility="gone">
<TextView
android:id="@+id/arrived_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_190"
android:layout_marginLeft="@dimen/dp_88"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:includeFontPadding="false"
android:text="@string/taxi_p_arrived_title"
android:textColor="@android:color/white"
android:textSize="@dimen/taxi_p_arrived_end_tv_size"/>
<TextView
android:id="@+id/arrived_end_station"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
app:layout_constraintTop_toTopOf="@+id/arrived_title"
app:layout_constraintBottom_toBottomOf="@+id/arrived_title"
app:layout_constraintLeft_toRightOf="@+id/arrived_title"
android:layout_marginLeft="@dimen/dp_30"
android:textSize="@dimen/taxi_p_arrived_end_tv_size"
android:includeFontPadding="false"
android:textStyle="bold"/>
<TextView
android:id="@+id/arrived_end_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/arrived_title"
app:layout_constraintTop_toBottomOf="@+id/arrived_title"
android:layout_marginTop="@dimen/dp_30"
android:textColor="@color/taxi_p_arrive_end_tip_color"
android:textSize="@dimen/taxi_p_arrived_end_tip_size"
android:text="@string/taxi_p_arrived_end_tips"/>
<View
android:layout_width="@dimen/dp_18"
android:layout_height="0dp"
android:background="@color/taxi_p_arrive_end_bg_line_color"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@+id/arrived_title"
app:layout_constraintBottom_toBottomOf="@+id/arrived_end_tip"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -3,8 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:taxi_right_bottom_radius="40px"
app:taxi_left_bottom_radius="40px">
app:taxi_right_bottom_radius="@dimen/dp_40"
app:taxi_left_bottom_radius="@dimen/dp_40">
<com.amap.api.maps.TextureMapView
android:id="@+id/taxi_p_order_amap_view"

View File

@@ -47,4 +47,10 @@
<dimen name="taxi_p_v2x_notification_icon_size">120px</dimen>
<dimen name="taxi_p_v2x_notification_text_size">39px</dimen>
<dimen name="taxi_p_v2x_notification_text_margin_left">20px</dimen>
<dimen name="taxi_p_arrived_end_tv_size">82px</dimen>
<dimen name="taxi_p_arrived_end_tip_size">42px</dimen>
<dimen name="taxi_p_speed_size">120px</dimen>
<dimen name="taxi_p_progress_des_size">28px</dimen>
</resources>

View File

@@ -24,6 +24,12 @@
<dimen name="module_mogo_och_operation_status_bg_width">120px</dimen>
<dimen name="module_mogo_och_operation_status_bg_height">120px</dimen>
<dimen name="taxi_p_arrived_end_tv_size">82px</dimen>
<dimen name="taxi_p_arrived_end_tip_size">42px</dimen>
<dimen name="taxi_p_speed_size">120px</dimen>
<dimen name="taxi_p_progress_des_size">28px</dimen>
<dimen name="module_mogo_och_operation_status_padding">83px</dimen>
<dimen name="module_mogo_och_autopilot_order_m_t">40px</dimen>

View File

@@ -25,4 +25,9 @@
<color name="taxi_p_traffic_light_yellow_color_down">#FF9B00</color>
<color name="taxi_p_v2x_notification_bg_color">#80000000</color>
<color name="taxi_p_arrive_end_bg_line_color">#F8B70A</color>
<color name="taxi_p_arrive_end_tip_color">#C6D9FA</color>
<color name="taxi_p_speed_color">#D1193D66</color>
</resources>

View File

@@ -108,4 +108,10 @@
<dimen name="taxi_p_v2x_notification_icon_size">120px</dimen>
<dimen name="taxi_p_v2x_notification_text_size">39px</dimen>
<dimen name="taxi_p_v2x_notification_text_margin_left">20px</dimen>
<dimen name="taxi_p_arrived_end_tv_size">82px</dimen>
<dimen name="taxi_p_arrived_end_tip_size">42px</dimen>
<dimen name="taxi_p_speed_size">120px</dimen>
<dimen name="taxi_p_progress_des_size">28px</dimen>
</resources>

View File

@@ -20,4 +20,8 @@
<string name="module_och_taxi_order_server_end">服务完成</string>
<string name="taxi_p_arrive_to_start">准备出发</string>
<string name="taxi_p_start_to_end">正在前往目的地</string>
<string name="taxi_p_arrive_end_tts_200">即将到达目的地,请您收好好随声物品,准备下车</string>
<string name="taxi_p_arrive_end_tts">已达到目的地,请从右侧下车,感谢乘坐蘑菇车联无人驾驶车</string>
<string name="taxi_p_arrived_title">已到达</string>
<string name="taxi_p_arrived_end_tips">感谢您使用蘑菇车联自动驾驶出行服务,期待下次与您相遇</string>
</resources>

View File

@@ -10,4 +10,13 @@
<style name="och_speed_style2">
<item name="android:textSize">32px</item>
</style>
<!--自定义seekbarstyle-->
<style name="CustomSeekbarStyle" >
<item name="android:height">20px</item>
<item name="android:width">248px</item>
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@drawable/taxi_p_seekbar_calculator_layer</item>
<item name="android:thumb">@drawable/taxi_p_seekbar_point_icon</item>
</style>
</resources>

View File

@@ -8,6 +8,8 @@ import android.util.Log;
import androidx.annotation.Nullable;
import com.amap.api.maps.CoordinateConverter;
import com.amap.api.maps.model.LatLng;
import com.elegant.network.utils.GsonUtil;
import com.mogo.cloud.commons.utils.CoordinateUtils;
import com.mogo.commons.debug.DebugConfig;
@@ -1047,7 +1049,6 @@ public class MogoOCHTaxiModelNew {
@Override
public void onAutopilotRotting(MessagePad.GlobalPathResp routeList) {
if (null != routeList && routeList.getWayPointsList().size() > 0){
// mAutopilotPlanningCallback.routeResult(routeList.getModels());
updateOrderRoute(routeList.getWayPointsList());
}
}
@@ -1065,14 +1066,7 @@ public class MogoOCHTaxiModelNew {
*/
public void updateOrderRoute(List<MessagePad.Location> models) {
List<OrderRouteUpdateReqBean.Result> points = new ArrayList<>();
for (int i =0; i < models.size(); i++){
OrderRouteUpdateReqBean.Result point = new OrderRouteUpdateReqBean.Result();
point.latitude = models.get(i).getLatitude();
point.longitude = models.get(i).getLongitude();
points.add(point);
}
List<OrderRouteUpdateReqBean.Result> points = CoordinateConverterFrom84ForList(mContext,models);
OCHTaxiServiceManagerNew.getInstance().updateOrderRoute(mContext, mCurrentOCHOrder.orderNo
, points, new OCHTaxiServiceCallback<BaseData>() {
@@ -1088,5 +1082,25 @@ public class MogoOCHTaxiModelNew {
});
}
private List<OrderRouteUpdateReqBean.Result> CoordinateConverterFrom84ForList(Context mContext, List<MessagePad.Location> mogoLatLngList) {
List<OrderRouteUpdateReqBean.Result> points = new ArrayList<>();
for (MessagePad.Location m : mogoLatLngList) {
LatLng mogoLatLng = CoordinateConverterFrom84(mContext, m);
OrderRouteUpdateReqBean.Result result = new OrderRouteUpdateReqBean.Result();
result.latitude = mogoLatLng.latitude;
result.longitude = mogoLatLng.longitude;
points.add(result);
}
return points;
}
private LatLng CoordinateConverterFrom84(Context mContext, MessagePad.Location mogoLatLng) {
CoordinateConverter mCoordinateConverter = new CoordinateConverter(mContext);
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS);
mCoordinateConverter.coord(new LatLng(mogoLatLng.getLatitude(), mogoLatLng.getLongitude()));
LatLng latLng = mCoordinateConverter.convert();
return latLng;
}
}

View File

@@ -1,5 +1,6 @@
package com.mogo.och.taxi.ui;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
@@ -10,8 +11,11 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.FragmentTransaction;
import com.amap.api.maps.CoordinateConverter;
import com.amap.api.maps.model.LatLng;
import com.mogo.commons.debug.DebugConfig;
import com.mogo.eagle.core.data.autopilot.AutopilotRouteInfo;
import com.mogo.eagle.core.data.map.MogoLatLng;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.module.common.MogoApisHandler;
import com.mogo.och.taxi.R;
@@ -22,6 +26,10 @@ import com.mogo.och.taxi.model.MogoOCHTaxiModelNew;
import com.mogo.och.taxi.presenter.OCHTaxiPresenter;
import com.mogo.och.taxi.utils.PinYinUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -317,21 +325,224 @@ public class OCHTaxiFragment extends BaseOchTaxiTabFragment<OCHTaxiFragment, OCH
MogoOCHTaxiModelNew.getInstance().setOnTheWayToEndStation();
});
findViewById(R.id.test_bar_send_route).setOnClickListener(v -> {
String listStr = "{\"models\":[{\n" +
"\t\t\"lat\": 40.19927810144466,\n" +
"\t\t\"lon\": 116.73527259387767\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19927836356079,\n" +
"\t\t\"lon\": 116.73513114732762\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19927759500293,\n" +
"\t\t\"lon\": 116.73497660879111\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.199264819842284,\n" +
"\t\t\"lon\": 116.73480063747202\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1992510141554,\n" +
"\t\t\"lon\": 116.73463922037767\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.199245872804,\n" +
"\t\t\"lon\": 116.73445960685193\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924673374912,\n" +
"\t\t\"lon\": 116.73427704009703\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924747108264,\n" +
"\t\t\"lon\": 116.7340707102972\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924828745573,\n" +
"\t\t\"lon\": 116.73385916927226\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924941093133,\n" +
"\t\t\"lon\": 116.73364048294795\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924939253381,\n" +
"\t\t\"lon\": 116.73340837408566\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19924949105934,\n" +
"\t\t\"lon\": 116.73317368725336\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19925040039033,\n" +
"\t\t\"lon\": 116.73296532811216\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1992515355653,\n" +
"\t\t\"lon\": 116.73277787366743\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1992512720328,\n" +
"\t\t\"lon\": 116.73263377253741\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.199205174954606,\n" +
"\t\t\"lon\": 116.73249773114644\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1991015743076,\n" +
"\t\t\"lon\": 116.7324219601283\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.198971862686285,\n" +
"\t\t\"lon\": 116.73239393296355\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19883883071582,\n" +
"\t\t\"lon\": 116.73237676435652\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19870171355796,\n" +
"\t\t\"lon\": 116.73236052150362\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1985491853193,\n" +
"\t\t\"lon\": 116.73234157857011\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1983890047355,\n" +
"\t\t\"lon\": 116.73232167996464\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1982209877466,\n" +
"\t\t\"lon\": 116.73230101645792\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.198037574138326,\n" +
"\t\t\"lon\": 116.73227735486083\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19787327856243,\n" +
"\t\t\"lon\": 116.73225676816314\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19771917207499,\n" +
"\t\t\"lon\": 116.73223814728027\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197548305175935,\n" +
"\t\t\"lon\": 116.73221624705808\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19739568979691,\n" +
"\t\t\"lon\": 116.73219618210774\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19724703821575,\n" +
"\t\t\"lon\": 116.73217598293311\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1970956560885,\n" +
"\t\t\"lon\": 116.73215773721505\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19697703483188,\n" +
"\t\t\"lon\": 116.73214337172284\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19687000725696,\n" +
"\t\t\"lon\": 116.73210037067965\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.196833449601726,\n" +
"\t\t\"lon\": 116.73196646708011\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19685833847804,\n" +
"\t\t\"lon\": 116.73181315361103\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.196889170203264,\n" +
"\t\t\"lon\": 116.73164355747393\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19692242860347,\n" +
"\t\t\"lon\": 116.7314555399657\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19696431701069,\n" +
"\t\t\"lon\": 116.7312261834129\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19700025925464,\n" +
"\t\t\"lon\": 116.73102774016093\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19703414798773,\n" +
"\t\t\"lon\": 116.73084270562073\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19707287604138,\n" +
"\t\t\"lon\": 116.73062835248406\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19710951629977,\n" +
"\t\t\"lon\": 116.73041744082339\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19714593807105,\n" +
"\t\t\"lon\": 116.73021414314803\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197183297026285,\n" +
"\t\t\"lon\": 116.7300057066447\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.1972247359487,\n" +
"\t\t\"lon\": 116.7297751515664\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19726518822745,\n" +
"\t\t\"lon\": 116.72954958923812\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19730538240706,\n" +
"\t\t\"lon\": 116.72932440756041\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19734272112662,\n" +
"\t\t\"lon\": 116.72911631453036\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197379191549075,\n" +
"\t\t\"lon\": 116.72890982812105\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197417565369314,\n" +
"\t\t\"lon\": 116.72869447869044\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19746052080799,\n" +
"\t\t\"lon\": 116.72845641541247\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19750040582118,\n" +
"\t\t\"lon\": 116.72823569991117\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19753999704064,\n" +
"\t\t\"lon\": 116.72801998373052\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19757796882569,\n" +
"\t\t\"lon\": 116.72781280504363\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197617062364586,\n" +
"\t\t\"lon\": 116.72759949431683\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19765391602761,\n" +
"\t\t\"lon\": 116.72739776789756\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19768973009218,\n" +
"\t\t\"lon\": 116.72719980764646\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.197726191028785,\n" +
"\t\t\"lon\": 116.72699719861669\n" +
"\t}, {\n" +
"\t\t\"lat\": 40.19776233489642,\n" +
"\t\t\"lon\": 116.72679516155276\n" +
"\t}]}\n";
List<MessagePad.Location> list = new ArrayList<>();
for (int i = 0; i < 200 ; i++){
MessagePad.Location.Builder builder = MessagePad.Location.newBuilder();
if (i <= 100){
builder.setLatitude(40.199248903658166);
builder.setLongitude(116.73435586102245 + i * 0.0001);
}else {
builder.setLatitude(40.199248903658166 + i * 0.0001);
builder.setLongitude(116.73435586102245 + 100 * 0.0001);
try {
JSONObject jsonObject = new JSONObject(listStr);
JSONArray jsonElements = jsonObject.getJSONArray("models");
for (int i = 0; i < jsonElements.length(); i++){
JSONObject s = jsonElements.getJSONObject(i);
MessagePad.Location.Builder builder = MessagePad.Location.newBuilder();
builder.setLatitude(s.getDouble("lat"));
builder.setLongitude(s.getDouble("lon"));
list.add(builder.build());
}
list.add(builder.build());
List<MessagePad.Location> list1 = CoordinateConverterFrom84ForList(getContext(),list);
MogoOCHTaxiModelNew.getInstance().updateOrderRoute(list1);
} catch (JSONException e) {
e.printStackTrace();
}
MogoOCHTaxiModelNew.getInstance().updateOrderRoute(list);
});
}
public List<MessagePad.Location> CoordinateConverterFrom84ForList(Context mContext, List<MessagePad.Location> mogoLatLngList) {
List<MessagePad.Location> list = new ArrayList<>();
for (MessagePad.Location m : mogoLatLngList) {
LatLng mogoLatLng = CoordinateConverterFrom84(mContext, m);
MessagePad.Location.Builder builder = MessagePad.Location.newBuilder();
builder.setLatitude(mogoLatLng.latitude);
builder.setLongitude(mogoLatLng.longitude);
list.add(builder.build());
}
return list;
}
public LatLng CoordinateConverterFrom84(Context mContext, MessagePad.Location mogoLatLng) {
CoordinateConverter mCoordinateConverter = new CoordinateConverter(mContext);
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS);
mCoordinateConverter.coord(new LatLng(mogoLatLng.getLatitude(), mogoLatLng.getLongitude()));
LatLng latLng = mCoordinateConverter.convert();
return latLng;
}
public void clickTestBar(){
View testBar = findViewById(R.id.module_och_taxi_order_status_change_test_bar);
if (testBar.getVisibility() == View.VISIBLE) {

View File

@@ -3,8 +3,8 @@ package com.mogo.functions.test
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import com.mogo.eagle.core.function.hmi.ui.MoGoHmiFragment
import com.mogo.eagle.core.function.main.MainLauncherActivity
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
@@ -14,6 +14,7 @@ import org.junit.runner.RunWith
import record_cache.RecordPanelOuterClass
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.random.Random
@@ -31,7 +32,7 @@ class AutoPilotBadCaseTest {
@ExperimentalCoroutinesApi
@Test
fun showBadCaseEntrance1(): Unit = runBlocking(Dispatchers.Main) {
delay(5000)
ensureMoGoHmiFragmentShow()
var index = 0
(1 until 50)
.map { it }
@@ -61,7 +62,7 @@ class AutoPilotBadCaseTest {
@ExperimentalCoroutinesApi
@Test
fun showBadCaseEntrance2(): Unit = runBlocking(Dispatchers.Main) {
delay(5000)
ensureMoGoHmiFragmentShow()
var index = 0
(1 until 50)
.map { it }
@@ -118,4 +119,29 @@ class AutoPilotBadCaseTest {
.collect()
delay(TimeUnit.HOURS.toMillis(2))
}
private suspend fun ensureMoGoHmiFragmentShow(): MoGoHmiFragment = suspendCancellableCoroutine {
launch.onActivity { itx ->
val executor = Executors.newSingleThreadScheduledExecutor()
executor.scheduleAtFixedRate({
var find =
itx.supportFragmentManager.fragments.find { it is MoGoHmiFragment } as? MoGoHmiFragment
while (find == null) {
find =
itx.supportFragmentManager.fragments.find { it is MoGoHmiFragment } as? MoGoHmiFragment
}
while (!find.isResumed) {
Thread.sleep(500)
}
it.resumeWith(Result.success(find))
try {
Thread.sleep(500)
executor.shutdownNow()
} catch (e: Throwable) {
e.printStackTrace()
}
}, 50, 500, TimeUnit.MILLISECONDS)
}
}
}

View File

@@ -28,7 +28,7 @@ ext {
androidxcardview : "androidx.cardview:cardview:1.0.0",
localbroadcastmanager : "androidx.localbroadcastmanager:localbroadcastmanager:1.0.0",
// flexbox
flexbox : 'com.google.android:flexbox:2.0.1',
flexbox : 'com.google.android.flexbox:flexbox:3.0.0',
// 测试
junit : "junit:junit:4.12",
androidxjunit : "androidx.test.ext:junit:1.1.2",

View File

@@ -35,6 +35,7 @@ import com.zhidao.support.adas.high.AdasManager
import com.zhidao.support.adas.high.AdasOptions
import com.zhidao.support.adas.high.bean.IPCUpgradeInfo
import com.zhidao.support.adas.high.common.Constants
import com.zhidao.support.adas.high.common.Constants.IPC_CONNECTION_STATUS
import com.zhidao.support.adas.high.common.CupidLogUtils
import io.netty.channel.Channel
import java.util.concurrent.TimeUnit
@@ -332,4 +333,11 @@ class MoGoAutopilotProvider :
override fun getGlobalPath() {
AdasManager.getInstance().sendGlobalPathReq()
}
/**
* 车机与工控机是否连上了
*/
override fun isConnected(): Boolean {
return AdasManager.getInstance().ipcConnectionStatus == IPC_CONNECTION_STATUS.CONNECTED
}
}

View File

@@ -82,6 +82,7 @@ dependencies {
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.androidxrecyclerview
implementation rootProject.ext.dependencies.flexbox
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation rootProject.ext.dependencies.mogoserviceapi

View File

@@ -8,6 +8,7 @@ import com.mogo.eagle.core.data.chain.ChainLogParam
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchManager
import com.zhjt.mogo_core_function_devatools.trace.TraceManager.Companion.traceManager
import record_cache.RecordPanelOuterClass
@@ -56,8 +57,11 @@ class DevaToolsProvider : IDevaToolsProvider {
BadCaseManager.onReceiveBadCaseRecord(record)
}
override fun showFeedbackWindow(ctx: Context) {
FeedbackManager.showFeedbackWindow(ctx)
}
override fun onDestroy() {
MogoLogCatchManager.onDestroy()
}
}

View File

@@ -4,6 +4,7 @@ import android.transition.AutoTransition
import android.transition.TransitionManager
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.LifecycleCoroutineScope
@@ -16,9 +17,10 @@ import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.kotlin.lifecycleOwner
import com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.kotlin.toast
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.eagle.core.utilcode.util.Utils
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCasePresenter
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCaseView
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
@@ -36,8 +38,7 @@ internal object BadCaseManager : LifecycleEventObserver {
* 超过此时间case入口自动消失
*/
private val CASE_EXPIRE_DURATION: Long =
TimeUnit.HOURS.toMillis(4)/* TimeUnit.SECONDS.toMillis(10) */
private val CASE_EXPIRE_DURATION: Long = TimeUnit.HOURS.toMillis(4)/* TimeUnit.SECONDS.toMillis(10) */
private var onShow: (() -> Unit)? = null
private var onHide: (() -> Unit)? = null
@@ -190,20 +191,20 @@ internal object BadCaseManager : LifecycleEventObserver {
hideFloat = null
},
onSelect = { reason ->
val uploadResult =
presenter.upload(mutableMapOf<String, String>().also { itx ->
itx["carLicense"] = MoGoAiCloudClientConfig.getInstance().sn
itx["filename"] = record.fileName ?: ""
itx["filesize"] = record.total.toString()
itx["key"] = record.key ?: ""
itx["reason"] = reason.reason ?: ""
itx["duration"] = record.duration.toInt().toString()
itx["timestamp"] = record.timestamp
})
val uploadResult = presenter.upload(mutableMapOf<String, String>().also { itx ->
itx["carLicense"] = MoGoAiCloudClientConfig.getInstance().sn
itx["filename"] = record.fileName ?: ""
itx["filesize"] = record.total.toString()
itx["key"] = record.key ?: ""
itx["reason"] = reason.reason ?: ""
itx["duration"] = record.duration.toInt().toString()
itx["timestamp"] = record.timestamp
itx["channel"] = "0"
})
if (uploadResult == null || uploadResult.code != 200) {
ToastUtils.showShort("接管反馈失败")
it.context.toast("上报失败")
} else {
ToastUtils.showShort("接管反馈成功")
it.context.toast("上报成功")
record.consumed = true
withContext(Dispatchers.IO) {
presenter.deleteRecord(record)
@@ -246,14 +247,11 @@ internal object BadCaseManager : LifecycleEventObserver {
}
}
private fun showBadCaseFloat(
onDismiss: () -> Unit,
onSelect: suspend (reason: Reason) -> Unit
) {
private fun showBadCaseFloat(onDismiss: () -> Unit, onSelect:suspend (reason: Reason) -> Unit) {
val context = viewHolder?.get()?.context ?: Utils.getApp()
BadCaseView(context).also {
it.register(record, onDismiss, onSelect)
hideFloat = CallerHmiManager.showBadCaseFloat(floatView = it)
BadCaseView(context).also { itx ->
itx.register(record, onDismiss, onSelect)
hideFloat = CallerHmiManager.showFloatWindow("BadCaseFloat", floatView = itx, WindowManager.LayoutParams().also { it.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE})
}
}

View File

@@ -1,28 +0,0 @@
package com.zhjt.mogo_core_function_devatools.badcase.api.entity
import androidx.annotation.Keep
import com.google.gson.annotations.Expose
@Keep
internal class BadCaseResponse {
var code: Int = -1
var data: List<Reason>? = null
var msg: String? = null
var success: Boolean = false
var total: Int = -1
@Expose(serialize = false, deserialize = false)
var isBuildIn: Boolean = false
@Keep
class Reason {
var id: String? = null
var reason: String? = null
/**
* 业务字段,不参与序列化和反序列化
*/
@Expose(deserialize = false, serialize = false)
var isChecked: Boolean = false
}
}

View File

@@ -2,7 +2,7 @@ package com.zhjt.mogo_core_function_devatools.badcase.biz
import android.util.Log
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.Repository
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
@@ -12,7 +12,7 @@ internal class BadCasePresenter: IBadCasePresenter {
Repository()
}
override suspend fun loadBadCases() = repository.loadBadCases()
override suspend fun loadBadCases(isDriven: Boolean) = repository.loadBadCases(isDriven)
override suspend fun insertRecord(record: AutoPilotRecord) {
try {
@@ -49,4 +49,8 @@ internal class BadCasePresenter: IBadCasePresenter {
Log.d(BadCaseManager.TAG, " --- 2 ----")
return repository.getLastModified()
}
override suspend fun getTaskId(): Int {
return repository.getTaskId()
}
}

View File

@@ -21,7 +21,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.kotlin.*
import com.mogo.eagle.core.utilcode.rv.divider.CommonDividerItemDecoration
import com.zhjt.mogo_core_function_devatools.R
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
import kotlinx.android.synthetic.main.layout_badcase_collect.view.*
import kotlinx.coroutines.launch
@@ -58,7 +58,7 @@ internal class BadCaseView: ConstraintLayout {
LayoutInflater.from(context).inflate(R.layout.layout_badcase_collect, this, true)
background = ColorDrawable(Color.parseColor("#F0151D41"))
isClickable = true
layoutParams = ViewGroup.LayoutParams(960.toPixels().toInt(), 1528.toPixels().toInt())
layoutParams = ViewGroup.LayoutParams(960.PX, 1528.PX)
close?.onClick {
onDismiss?.invoke()
}
@@ -69,8 +69,8 @@ internal class BadCaseView: ConstraintLayout {
}
}
ok?.also {
val enabled = gradient(radius = 16.toPixels().toInt(), orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252))
val disabled = gradient(radius = 16.toPixels().toInt(), orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(24, 71, 129), endColor = Color.rgb(21, 46, 129))
val enabled = gradient(radius = 16.PX, orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252))
val disabled = gradient(radius = 16.PX, orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(24, 71, 129), endColor = Color.rgb(21, 46, 129))
it.background = object : StateListDrawable() {}.also { itx ->
itx.addState(intArrayOf(android.R.attr.state_enabled), enabled)
itx.addState(StateSet.WILD_CARD, disabled)
@@ -86,7 +86,7 @@ internal class BadCaseView: ConstraintLayout {
scope.launchWhenCreated {
time_of_take_over?.text = "接管时间: ${SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.getDefault()).format(record?.toLongTime() ?: System.currentTimeMillis())}"
showLoading()
presenter.loadBadCases().also {
presenter.loadBadCases(true).also {
cases = it
refresh(it)
}
@@ -101,7 +101,7 @@ internal class BadCaseView: ConstraintLayout {
it.addItemDecoration(
CommonDividerItemDecoration
.Builder()
.verticalInnerSpace(50.toPixels().toInt())
.verticalInnerSpace(50.PX)
.build())
it.adapter = object : RecyclerView.Adapter<BadCaseViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BadCaseViewHolder = BadCaseViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_badcase_item, parent, false))

View File

@@ -1,13 +1,13 @@
package com.zhjt.mogo_core_function_devatools.badcase.biz
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
internal interface IBadCasePresenter {
suspend fun loadBadCases(): List<BadCaseResponse.Reason>
suspend fun loadBadCases(isDriven: Boolean): List<Reason>
suspend fun updateLastModified(timestamp: Long)
@@ -20,4 +20,6 @@ internal interface IBadCasePresenter {
suspend fun getUnConsumedRecords(): List<AutoPilotRecord>
suspend fun deleteRecord(record: AutoPilotRecord)
suspend fun getTaskId(): Int
}

View File

@@ -3,8 +3,8 @@ package com.zhjt.mogo_core_function_devatools.badcase.repository
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.BadCaseDbModel
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.BadCaseNetModel
@@ -25,8 +25,8 @@ internal class Repository {
BadCaseStore
}
suspend fun loadBadCases(): List<Reason> {
return net.get()?.data?.takeIf { it.isNotEmpty() }?.also { store.updateRecords(it) } ?: store.records().takeIf { it.isNotEmpty() } ?: getBuildIn()
suspend fun loadBadCases(isDriven: Boolean): List<Reason> {
return net.get()?.data?.takeIf { it.isNotEmpty() }?.also { store.updateRecords(it, isDriven) } ?: store.records(isDriven).takeIf { it.isNotEmpty() } ?: getBuildIn(isDriven)
}
suspend fun uploadLastModified(timestamp: Long) {
@@ -38,40 +38,44 @@ internal class Repository {
return store.getLastModified()
}
private fun getBuildIn(): List<Reason> {
private fun getBuildIn(isDriven: Boolean): List<Reason> {
CallerLogger.d("$M_DEVA${BadCaseManager.TAG}", "-- load cases from buildin -- 1 --")
val data = mutableListOf<Reason>()
data += Reason().also {
it.id = "1"
it.reason = "变道有干扰"
}
data += Reason().also {
it.id = "2"
it.reason = "遇红绿灯未停车"
}
data += Reason().also {
it.id = "3"
it.reason = "遇障碍物未停车"
}
data += Reason().also {
it.id = "4"
it.reason = "无法绕行"
}
data += Reason().also {
it.id = "5"
it.reason = "画龙"
}
data += Reason().also {
it.id = "6"
it.reason = "转弯过于靠近路侧"
}
data += Reason().also {
it.id = "7"
it.reason = "无故退出自动驾驶"
}
data += Reason().also {
it.id = "8"
it.reason = "其它"
if (isDriven) {
data += Reason().also {
it.id = "1"
it.reason = "变道有干扰"
}
data += Reason().also {
it.id = "2"
it.reason = "遇红绿灯未停车"
}
data += Reason().also {
it.id = "3"
it.reason = "遇障碍物未停车"
}
data += Reason().also {
it.id = "4"
it.reason = "无法绕行"
}
data += Reason().also {
it.id = "5"
it.reason = "画龙"
}
data += Reason().also {
it.id = "6"
it.reason = "转弯过于靠近路侧"
}
data += Reason().also {
it.id = "7"
it.reason = "无故退出自动驾驶"
}
data += Reason().also {
it.id = "8"
it.reason = "其它"
}
} else {
TODO()
}
return data
}
@@ -91,4 +95,8 @@ internal class Repository {
suspend fun getAllUnConsumedRecord(): List<AutoPilotRecord>? {
return db.dao().getAllUnConsumedRecords()
}
suspend fun getTaskId(): Int {
return store.getTaskIdAndIncrement()
}
}

View File

@@ -4,9 +4,9 @@ import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.network.MoGoRetrofitFactory
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
import com.zhjt.mogo_core_function_devatools.badcase.api.BadCaseApi
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.BadCaseApi
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseHost
internal class BadCaseNetModel {

View File

@@ -1,7 +1,7 @@
package com.zhjt.mogo_core_function_devatools.badcase.api
package com.zhjt.mogo_core_function_devatools.badcase.repository.net.api
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import retrofit2.Response
import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded

View File

@@ -0,0 +1,45 @@
package com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity
import androidx.annotation.Keep
import com.google.gson.annotations.Expose
@Keep
internal class BadCaseResponse {
var code: Int = -1
var data: List<Reason>? = null
var msg: String? = null
var success: Boolean = false
var total: Int = -1
@Expose(serialize = false, deserialize = false)
var isBuildIn: Boolean = false
@Keep
class Reason {
var id: String? = null
var reason: String? = null
/**
* 业务字段,不参与序列化和反序列化
*/
@Expose(deserialize = false, serialize = false)
var isChecked: Boolean = false
override fun equals(other: Any?): Boolean {
if (javaClass != other?.javaClass) return false
other as Reason
if (id != other.id) return false
if (reason != other.reason) return false
if (isChecked != other.isChecked) return false
return true
}
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + (reason?.hashCode() ?: 0)
result = 31 * result + isChecked.hashCode()
return result
}
}
}

View File

@@ -1,4 +1,4 @@
package com.zhjt.mogo_core_function_devatools.badcase.api.entity
package com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity
import androidx.annotation.Keep

View File

@@ -7,7 +7,7 @@ import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.util.Utils
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.generated.BadCauses
import com.zhjt.mogo_core_function_devatools.badcase.generated.Cause
import kotlinx.coroutines.FlowPreview
@@ -55,15 +55,10 @@ internal object BadCaseStore {
private val store: DataStore<BadCauses> by lazy {
DataStoreFactory.create(serializer = serializer) {
File(
Utils.getApp().filesDir,
"bad_cases.pb"
)
}
DataStoreFactory.create(serializer = serializer) { File(Utils.getApp().filesDir, "bad_cases.pb") }
}
suspend fun updateRecords(reasons: List<Reason>): BadCauses {
suspend fun updateRecords(reasons: List<Reason>, isDriven: Boolean): BadCauses {
CallerLogger.d("$M_DEVA${BadCaseManager.TAG}", "--- updateRecords ---")
val data = mutableListOf<Cause>()
reasons.forEach { itx ->
@@ -74,7 +69,11 @@ internal object BadCaseStore {
}
}
return store.updateData { itx ->
itx.toBuilder().clearData().addAllData(data).build()
if (isDriven) {
itx.toBuilder().clearDrivenData().addAllDrivenData(data).build()
} else {
itx.toBuilder().clearDrivingData().addAllDrivingData(data).build()
}
}
}
@@ -101,10 +100,10 @@ internal object BadCaseStore {
}
@OptIn(FlowPreview::class)
suspend fun records(): List<Reason> {
CallerLogger.d("$M_DEVA${BadCaseManager.TAG}", "-- load cases from pb -- 1 -- ")
suspend fun records(isDriven: Boolean): List<Reason> {
val causes = store.data.firstOrNull()
return causes?.dataList?.map {
val list = if (isDriven) causes?.drivenDataList else causes?.drivingDataList
return list?.map {
Reason().also { itx ->
itx.id = it.id
itx.reason = it.reason
@@ -114,4 +113,18 @@ internal object BadCaseStore {
acc
} ?: emptyList()
}
suspend fun getTaskIdAndIncrement(): Int {
val causes = store.data.firstOrNull()
val ret = causes?.taskId ?: 0
return ret.also {
store.updateData { itx ->
var old = ret
if (old == Int.MAX_VALUE) {
old = 0
}
itx.toBuilder().setTaskId(old + 1).build()
}
}
}
}

View File

@@ -0,0 +1,210 @@
package com.zhjt.mogo_core_function_devatools.feedback
import android.content.Context
import android.text.TextUtils
import android.util.Log
import android.view.WindowManager
import android.widget.TextView
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
import com.mogo.eagle.core.utilcode.kotlin.onDetach
import com.mogo.eagle.core.utilcode.kotlin.safeCancel
import com.mogo.eagle.core.utilcode.kotlin.scope
import com.mogo.eagle.core.utilcode.kotlin.toast
import com.mogo.eagle.core.utilcode.mogo.toast.TipToast
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.zhjt.mogo_core_function_devatools.R
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.badcase.toRecord
import com.zhjt.mogo_core_function_devatools.feedback.biz.FeedBackView
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
import com.zhjt.mogo_core_function_devatools.feedback.biz.impl.FeedbackPresenter
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import record_cache.RecordPanelOuterClass
import java.lang.IllegalStateException
import kotlin.Result.Companion
internal object FeedbackManager {
const val TAG = "feedback"
private var hideFloat: (() -> Unit)? = null
private val presenter by lazy { FeedbackPresenter() }
@OptIn(ExperimentalCoroutinesApi::class)
private var autoPilotCallback = Channel<AutoPilotRecord>(Channel.RENDEZVOUS)
@Synchronized
get() = if (field.isClosedForReceive || field.isClosedForSend) {
field = Channel(Channel.RENDEZVOUS)
field
} else field
fun showFeedbackWindow(ctx: Context) {
CallerHmiManager.showFloatWindow("FeedbackWindow", FeedBackView(ctx).also { itx ->
itx.registerCallback(object : IFeedbackCallback {
override fun onClose() {
hideFloat?.invoke()
}
override fun onBadCaseItemClicked(reason: Reason) {
val oldData = itx.adapter.data ?: return
if (reason.isChecked) {
return
}
reason.isChecked = true
val badCase = oldData.firstOrNull() as? BadCase
badCase?.reasons?.filterNot { it.id == reason.id }?.forEach {
it.isChecked = false
}
itx.adapter.notifyItemChanged(0)
}
override fun onStartBadCaseRecord(record: TextView) {
if (!CallerAutoPilotManager.isConnected()) {
TipToast.shortTip("请检查车机与域控制器连接是否正常")
return
}
val data = itx.adapter.data ?: return
val badCase = data.firstOrNull() as? BadCase ?: return
val checked = badCase.reasons.find { it.isChecked }
if (checked == null) {
TipToast.shortTip("请选择一个Case")
return
}
record.scope.launch {
val taskId = presenter.getBadCaseTaskId()
val listener = object : IMoGoAutopilotIdentifyListener {
override fun onAutopilotRecordResult(recordPanel: RecordPanelOuterClass.RecordPanel) {
super.onAutopilotRecordResult(recordPanel)
val newRecord = recordPanel.toRecord() ?: return
Log.d(TAG, "-- 收到工控机录制任务回调 -- $recordPanel")
if (newRecord.type == 1 && newRecord.id == taskId) {
if (newRecord.stat == 100 || newRecord.stat == 101) {
Log.d(TAG, "录制Bag完成, 触发结束录制全量日志 ...")
stopRecordLog(newRecord)
launch {
send(newRecord)
}
}
if (newRecord.stat == 300) {
Log.d(TAG, "录制Bag开始, 触发录制全量日志 ...")
startRecordLog(newRecord)
}
}
}
}
CallerAutopilotIdentifyListenerManager.addListener("Feedback", listener)
record.onDetach {
CallerAutopilotIdentifyListenerManager.removeListener("Feedback")
hideFloat = null
}
record.text = "结束录制"
record.setTag(R.id.feed_back_badcase_tag, 1)
record.setTag(R.id.feed_back_badcase_taskid_tag, taskId)
recordBag(1, taskId, 20)
Log.d(TAG, "延时20秒开始....")
delay(20000) //延时20秒
Log.d(TAG, "延时20秒结束....")
stopRecordBag(1, taskId)
upload(record.context, badCase, checked)
}.also {
record.setTag(R.id.feed_back_badcase_job, it)
}
}
override fun onStopBadCaseRecord(record: TextView) {
val data = itx.adapter.data ?: return
val badCase = data.firstOrNull() as? BadCase ?: return
val checked = badCase.reasons.find { it.isChecked } ?: throw IllegalStateException("这种状态不存在")
val taskId = (record.getTag(R.id.feed_back_badcase_taskid_tag) as? Int) ?: throw IllegalStateException("TaskId 不存在")
val oldJob = record.getTag(R.id.feed_back_badcase_job) as? Job
record.scope.launch {
stopRecordBag(1, taskId)
oldJob?.safeCancel()
upload(record.context, badCase, checked)
}
}
})
}, WindowManager.LayoutParams().also { it.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN }).also { hideFloat = it }
}
private fun startRecordLog(record: AutoPilotRecord) {
//val fileName = record.fileName
//TODO zhongchao 添加全量日志开始录制
}
private fun stopRecordLog(newRecord: AutoPilotRecord) {
//val fileName = record.fileName
//TODO zhongchao 添加全量日志结束录制
}
private suspend fun upload(ctx: Context, badCase: BadCase, checked: Reason) {
val result = receive()
val remark = badCase.remark.text
presenter.upload(mutableMapOf<String, String>().also { itx ->
itx["carLicense"] = MoGoAiCloudClientConfig.getInstance().sn
itx["filename"] = result.fileName ?: ""
itx["filesize"] = result.total.toString()
itx["key"] = result.key ?: ""
itx["reason"] = checked.reason ?: ""
itx["duration"] = result.duration.toInt().toString()
itx["timestamp"] = result.timestamp
itx["channel"] = "1"
if (!TextUtils.isEmpty(remark)) {
itx["remark"] = remark.toString()
}
}).also {
if (it == null || it.code != 200) {
ctx.toast("上报失败")
} else {
ctx.toast("上报成功")
hideFloat?.invoke()
}
}
}
private suspend fun send(record: AutoPilotRecord) = autoPilotCallback.send(record)
private suspend fun receive(): AutoPilotRecord = autoPilotCallback.receive()
private suspend fun recordBag(type: Int, id: Int, duration: Int) = suspendCancellableCoroutine<Unit> {
val future = ThreadUtils.getIoPool().submit {
try {
CallerAutoPilotManager.recordPackage(type, id, duration)
it.resumeWith(Result.success(Unit))
} catch (t: Throwable) {
it.resumeWith(Companion.failure(t))
}
}
it.invokeOnCancellation {
try {
future.cancel(true)
} catch (t: Throwable) {
t.printStackTrace()
}
}
}
private suspend fun stopRecordBag(type: Int, id: Int) = suspendCancellableCoroutine<Unit> {
val future = ThreadUtils.getIoPool().submit {
try {
CallerAutoPilotManager.stopRecord(type, id)
it.resumeWith(Result.success(Unit))
} catch (t: Throwable) {
it.resumeWith(Companion.failure(t))
}
}
it.invokeOnCancellation {
try {
future.cancel(true)
} catch (t: Throwable) {
t.printStackTrace()
}
}
}
}

View File

@@ -0,0 +1,93 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.mogo.eagle.core.utilcode.kotlin.*
import com.zhjt.mogo_core_function_devatools.R
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.FeedbackAdapter
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
import com.zhjt.mogo_core_function_devatools.feedback.biz.impl.FeedbackPresenter
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
import kotlinx.android.synthetic.main.layout_fb.view.*
internal class FeedBackView : ConstraintLayout {
private var cb: IFeedbackCallback? = null
private val presenter by lazy {
FeedbackPresenter()
}
private val scope by lazy {
lifecycleOwner.lifecycleScope
}
internal val adapter by lazy {
FeedbackAdapter<Feedback>()
}
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
LayoutInflater.from(context).inflate(R.layout.layout_fb, this, true).also {
observe(arrayOf(ON_DESTROY)) { itx ->
if (itx == ON_DESTROY) {
cb = null
}
}
}
layoutParams = ViewGroup.LayoutParams(960.PX, 1528.PX)
close.onClick {
cb?.onClose()
}
top_mask?.background = gradient(orientation = GradientDrawable.Orientation.TOP_BOTTOM, startColor = Color.parseColor("#151D41"), endColor = Color.parseColor("#05151D41"))
background = ColorDrawable(Color.parseColor("#F0151D41"))
rv?.also {
it.fixGestureConflictForViews(listOf(R.id.et))
it.itemAnimator?.run {
changeDuration = 0
addDuration = 0
moveDuration = 0
removeDuration = 0
}
it.adapter = adapter
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
loadFeedbackAndRefresh()
}
}
private fun loadFeedbackAndRefresh() {
scope.launchWhenCreated {
showLoading()
presenter.loadFeedBacks().also {
adapter.data = it
}
hideLoading()
}
}
private fun showLoading() {
pb?.visibility = View.VISIBLE
}
private fun hideLoading() {
pb?.visibility = View.GONE
}
fun registerCallback(cb: IFeedbackCallback) {
this.cb = cb
this.adapter.setCallback(cb)
}
}

View File

@@ -0,0 +1,14 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
internal interface IFeedbackPresenter {
suspend fun loadFeedBacks(): List<Feedback>
suspend fun getBadCaseTaskId(): Int
suspend fun upload(params: Map<String, String>): UploadResult?
}

View File

@@ -0,0 +1,63 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz.adapter
import android.util.Log
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.BadCaseFBViewHolder
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base.FeedbackViewHolder
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
import com.zhjt.mogo_core_function_devatools.feedback.biz.diff.FeedbackDiffCallback
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
internal class FeedbackAdapter<T: Feedback>: RecyclerView.Adapter<FeedbackViewHolder<T>>() {
companion object {
const val ITEM_TYPE_BAD_CASE = 0x0101
}
private var cb: IFeedbackCallback? = null
var data: List<T>? = null
@Synchronized
set(value) {
val result = DiffUtil.calculateDiff(FeedbackDiffCallback(field, value))
result.dispatchUpdatesTo(this)
field = value
}
override fun getItemViewType(position: Int): Int {
val data = data ?: return super.getItemViewType(position)
when(val item = data[position]) {
is BadCase -> {
Log.d(FeedbackManager.TAG, "item->$item")
return ITEM_TYPE_BAD_CASE
}
}
return super.getItemViewType(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedbackViewHolder<T> {
when (viewType) {
ITEM_TYPE_BAD_CASE -> {
return BadCaseFBViewHolder(cb, parent) as FeedbackViewHolder<T>
}
else -> {
throw IllegalStateException("不支持ViewType: $viewType")
}
}
}
override fun onBindViewHolder(holder: FeedbackViewHolder<T>, position: Int) {
val item = data?.get(position) ?: return
holder.onBind(item, position)
}
override fun getItemCount(): Int = data?.size ?: 0
fun setCallback(cb: IFeedbackCallback) {
this.cb = cb
}
}

View File

@@ -0,0 +1,155 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.GradientDrawable.Orientation.LEFT_RIGHT
import android.graphics.drawable.StateListDrawable
import android.text.Selection
import android.text.TextUtils
import android.text.TextUtils.TruncateAt.END
import android.util.StateSet
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.google.android.flexbox.FlexboxLayout
import com.mogo.eagle.core.utilcode.kotlin.*
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.zhjt.mogo_core_function_devatools.R
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base.FeedbackViewHolder
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
@SuppressLint("SetTextI18n")
internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): FeedbackViewHolder<BadCase>(cb,
LayoutInflater
.from(parent.context)
.inflate(R.layout.layout_fb_badcase, parent, false)) {
private val flex by lazy {
itemView.findViewById<FlexboxLayout>(R.id.flex)
}
private val et by lazy {
itemView.findViewById<EditText>(R.id.et)
}
init {
itemView.findViewById<TextView>(R.id.record).also {
it.background = gradient(radius = 16.PX, orientation = LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252))
it.onClick { _ ->
val flag = (it.getTag(R.id.feed_back_badcase_tag) as? Int) ?: 0
if (flag == 0) {
cb?.onStartBadCaseRecord(it)
} else {
cb?.onStopBadCaseRecord(it)
}
}
}
itemView.findViewById<View>(R.id.et_root).also {
it.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX)
}
val words = itemView.findViewById<TextView>(R.id.words_count)
et.onClick {
et.requestFocus()
et.isFocusable = true
et.isFocusableInTouchMode = true
}
et.watch(
200,
onCountChanged = {
words.spannableText(listOf(it.toString(), "/200"), listOf(Color.parseColor("#5EBFFF"), Color.WHITE))
},
onTextChanged = {
data().remark.text = it?.toString() ?: ""
},
onReachMaxCountAction = {
ToastUtils.showShort("已超过最大字符数")
},
onGetFocus = {
it.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX, stroke = Color.parseColor("#5EBFFF"))
}
)
}
override fun onBind(data: BadCase, position: Int) {
super.onBind(data, position)
flex.refresh(data)
val text = data.remark.text
if (!TextUtils.isEmpty(text)) {
et.setText(text)
Selection.setSelection(et.text, et.text.length)
}
}
private fun FlexboxLayout.refresh(data: BadCase) {
val vh = (tag as? Map<*, *> ?: emptyMap<Reason, ViewHolder>()).toMutableMap()
if (vh.isEmpty()) {
data.reasons.forEach { itx ->
val view = getBadCaseView(context)
val check = view.findViewById<ImageView>(R.id.check)
check.background = StateListDrawable().also {
it.addState(intArrayOf(android.R.attr.state_selected), ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_check))
it.addState(StateSet.WILD_CARD, ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_default))
}
check.isSelected = itx.isChecked
val reason = view.findViewById<TextView>(R.id.reason)
reason.text = itx.reason
vh[itx] = ViewHolder(check, reason)
view.onClick {
cb?.onBadCaseItemClicked(itx)
}
view.layoutParams = FlexboxLayout.LayoutParams(FlexboxLayout.LayoutParams.MATCH_PARENT, FlexboxLayout.LayoutParams.WRAP_CONTENT).also {
it.flexBasisPercent = 0.5f
}
addView(view)
}
tag = vh
} else {
data.reasons.forEach {
(vh[it] as? ViewHolder)?.run {
check.isSelected = it.isChecked
reason.text = it.reason
}
}
}
}
private fun getBadCaseView(context: Context): View {
return LinearLayout(context).also { itx ->
itx.orientation = LinearLayout.HORIZONTAL
itx.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
itx.gravity = Gravity.CENTER_VERTICAL
//ImageView -- check
val check = ImageView(context)
check.layoutParams = LinearLayout.LayoutParams(70.PX, 70.PX)
check.id = R.id.check
itx.addView(check)
//TextView -- Reason
val reason = TextView(context)
reason.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
it.marginStart = 30.PX
it.marginEnd = 20.PX
}
reason.setTextColor(Color.WHITE)
reason.setTextSize(TypedValue.COMPLEX_UNIT_PX, 42.0f)
reason.maxLines = 1
reason.ellipsize = END
reason.id = R.id.reason
itx.addView(reason)
}
}
private data class ViewHolder(val check: ImageView, val reason: TextView)
}

View File

@@ -0,0 +1,22 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base
import android.view.View
import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
import java.util.concurrent.atomic.AtomicReference
internal open class FeedbackViewHolder<T: Feedback>(internal val cb: IFeedbackCallback?, view: View): RecyclerView.ViewHolder(view) {
private val data by lazy { AtomicReference<T>() }
fun data(): T {
return data.get()
}
@CallSuper
open fun onBind(data: T, position: Int) {
this.data.set(data)
}
}

View File

@@ -0,0 +1,28 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz.bean
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
internal sealed class Feedback {
class BadCase(var remark: Remark, var reasons: List<Reason>): Feedback() {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BadCase
if (reasons != other.reasons) return false
return true
}
override fun hashCode(): Int {
return reasons.hashCode()
}
}
}
/**
* 记录文本编辑框的状态
* @param text: 文件编辑框中输入的文字
* @param cursorPos: 光标位置
*/
data class Remark(var text: CharSequence = "", var cursorPos: Int = 0)

View File

@@ -0,0 +1,25 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz.diff
import androidx.recyclerview.widget.DiffUtil
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
internal class FeedbackDiffCallback<T: Feedback>(private val oldData: List<T>?, private val newData: List<T>?): DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldData?.size ?: 0
}
override fun getNewListSize(): Int = newData?.size ?: 0
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = oldData?.takeIf { it.size > oldItemPosition }?.equals(newData?.takeIf { it.size > newItemPosition }) ?: false
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldData?.get(oldItemPosition)
val newItem = newData?.get(newItemPosition)
if (oldItem == null || newItem == null) {
return false
}
return oldItem == newItem
}
}

View File

@@ -0,0 +1,28 @@
package com.zhjt.mogo_core_function_devatools.feedback.biz.impl
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCasePresenter
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.UploadResult
import com.zhjt.mogo_core_function_devatools.feedback.biz.IFeedbackPresenter
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Remark
internal class FeedbackPresenter: IFeedbackPresenter {
private val badCase by lazy {
BadCasePresenter()
}
override suspend fun loadFeedBacks(): List<Feedback> = mutableListOf<Feedback>().also {
//添加BadCase数据
it += BadCase(Remark(), badCase.loadBadCases(false))
}
override suspend fun getBadCaseTaskId(): Int {
return badCase.getTaskId()
}
override suspend fun upload(params: Map<String, String>): UploadResult? {
return badCase.upload(params)
}
}

View File

@@ -0,0 +1,28 @@
package com.zhjt.mogo_core_function_devatools.feedback.callback
import android.view.View
import android.widget.TextView
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
internal interface IFeedbackCallback {
/**
* 点击关闭弹窗按钮时回调
*/
fun onClose()
/**
* BadCase某一条目被点击了
*/
fun onBadCaseItemClicked(reason: Reason)
/**
* 点击开始录制
*/
fun onStartBadCaseRecord(record: TextView)
/**
* 点击停止录制
*/
fun onStopBadCaseRecord(record: TextView)
}

View File

@@ -6,7 +6,9 @@ option java_outer_classname = "BadCausesProto";
message BadCauses {
int64 lastModified = 1;
repeated Cause data = 2 ;
repeated Cause drivenData = 2 ; //被动触发BadCase数据
int32 taskId = 3;
repeated Cause drivingData = 4; //主动触发BadCase数据
}
message Cause {

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="0px" android:height="50px" />
</shape>

View File

@@ -103,7 +103,7 @@
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@android:style/Widget.Holo.ProgressBar.Large"
style="@android:style/Widget.Holo.Light.ProgressBar.Inverse"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@@ -2,15 +2,16 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
android:gravity="center_vertical"
tools:ignore="HardcodedText,PxUsage,ContentDescription">
<ImageView
android:id="@+id/check"
android:layout_width="70px"
android:layout_height="70px"
android:layout_marginStart="113px"/>
android:layout_marginStart="113px" />
<TextView
android:id="@+id/reason"

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:layout_width="match_parent"
tools:layout_height="match_parent"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="120px"/>
<ImageView
android:id="@+id/close"
android:layout_width="107px"
android:layout_height="107px"
android:layout_marginTop="66px"
android:layout_marginEnd="40px"
android:src="@drawable/icon_close_nor"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="PxUsage" />
<ProgressBar
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@android:style/Widget.Holo.Light.ProgressBar.Inverse"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="gone"/>
<View
android:id="@+id/top_mask"
android:layout_width="0dip"
android:layout_height="80px"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</merge>

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="HardcodedText,PxUsage">
<LinearLayout
android:id="@+id/ll_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center_vertical"
android:layout_marginTop="92px"
android:layout_marginStart="80px"
android:orientation="horizontal">
<View
android:layout_width="14px"
android:layout_height="50px"
android:background="#2966EC"
android:layout_marginEnd="19px"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="42px"
android:textColor="#ffffff"
android:text="Case上报"/>
</LinearLayout>
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/flex"
android:layout_width="0dip"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_title"
app:flexWrap="wrap"
app:flexDirection="row"
app:dividerDrawable="@drawable/flex_divider"
app:showDivider="middle"
app:justifyContent="flex_start"
android:layout_marginStart="80px"
android:layout_marginTop="54px" />
<TextView
android:id="@+id/supply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/flex"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="80px"
android:layout_marginTop="86px"
android:text="补充"
android:textColor="#ffffff"
android:textSize="36px" />
<LinearLayout
android:id="@+id/et_root"
android:layout_width="0dip"
android:layout_height="396px"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/supply"
app:layout_constraintEnd_toEndOf="parent"
android:paddingTop="30px"
android:paddingStart="25px"
android:paddingEnd="45px"
android:layout_marginStart="75px"
android:layout_marginEnd="95px"
android:layout_marginTop="32px"
android:orientation="vertical">
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:background="@null"
android:focusable="false"
android:gravity="start"
android:focusableInTouchMode="true"
android:inputType="textMultiLine"
android:textSize="36px"
android:textColorHint="#4CFFFFFF"
android:hint="Case细节描述"
android:textColor="#FFFFFF" />
<TextView
android:id="@+id/words_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="28px"
android:layout_gravity="end"
tools:text="126/200"/>
</LinearLayout>
<TextView
android:id="@+id/record"
android:layout_width="0px"
android:layout_height="126px"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="75px"
android:layout_marginEnd="95px"
android:layout_marginTop="40px"
android:textColor="#ffffff"
android:textSize="42px"
android:gravity="center"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@+id/et_root"
android:text="录制Case"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="feed_back_badcase_tag" type="id" />
<item name="feed_back_badcase_taskid_tag" type="id" />
<item name="feed_back_badcase_job" type="id" />
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View File

@@ -169,6 +169,10 @@ class WarningFloat {
this.config.isEnqueue = enqueue
}
fun softInputMode(mode: Int) = apply {
this.config.softInputMode = mode
}
/**
* 创建浮窗包括Activity浮窗和系统浮窗如若系统浮窗无权限先进行权限申请
*/

View File

@@ -56,6 +56,7 @@ internal class WarningFloatWindowHelper(
// 获取 WindowManager
windowManager = context.getSystemService(Service.WINDOW_SERVICE) as WindowManager
params = WindowManager.LayoutParams().apply {
// 设置窗口类型为应用子窗口和PopupWindow同类型
type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
format = PixelFormat.RGBA_8888
@@ -73,6 +74,10 @@ internal class WarningFloatWindowHelper(
x = config.locationPair.first
y = config.locationPair.second
}
//添加软键盘展示模式
if (config.softInputMode != 0) {
softInputMode = config.softInputMode
}
}
}
@@ -89,6 +94,7 @@ internal class WarningFloatWindowHelper(
// 为了避免创建的时候闪一下我们先隐藏视图不能直接设置GONE否则定位会出现问题
floatingView.visibility = View.INVISIBLE
// 将frameLayout添加到系统windowManager中
windowManager.addView(frameLayout, params)
// 在浮窗绘制完成的时候,设置初始坐标、执行入场动画

View File

@@ -19,6 +19,9 @@ data class WarningNotificationConfig(
var layoutId: Int? = null,
var layoutView: View? = null,
// 软键盘模式
var softInputMode: Int = 0,
// 当前浮窗的tag
var floatTag: String? = null,
// 是否正在执行动画

View File

@@ -6,6 +6,7 @@ import android.text.TextUtils
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.view.WindowManager.LayoutParams
import android.view.animation.OvershootInterpolator
import androidx.lifecycle.lifecycleScope
import com.alibaba.android.arouter.facade.annotation.Route
@@ -80,8 +81,6 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
private var toolsView: AutoPilotAndCheckView? = null
private var autoPilotToolsFloat: WarningFloat.Builder? = null
// 检测、自动驾驶速度设置
private var toolsViewFloat: WarningFloat.Builder? = null
@@ -223,6 +222,11 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
override fun showDebugPanelView() {
toggleDebugView()
}
override fun showFeedbackView() {
dismissToolsFloatView()
CallerDevaToolsManager.showFeedbackView(it)
}
})
}
toolsViewFloat = WarningFloat.with(it)
@@ -874,7 +878,8 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
}
override fun showBadCaseFloat(tag: String, floatView: View): () -> Unit {
override fun showFloatWindow(tag: String, floatView: View, attrs: LayoutParams?): () -> Unit {
var floatWindow: WarningFloat.Builder?
WarningFloat.with(context ?: Utils.getApp())
.setTag(tag)
.setLayout(floatView)
@@ -884,7 +889,7 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
.setAnimator(object : DefaultAnimator() {
override fun enterAnim(
view: View,
params: WindowManager.LayoutParams,
params: LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator? =
@@ -895,7 +900,7 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
override fun exitAnim(
view: View,
params: WindowManager.LayoutParams,
params: LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator? =
@@ -904,17 +909,20 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
})
.addWarningStatusListener(object : IMoGoWarningStatusListener {
override fun onDismiss() {
autoPilotToolsFloat = null
floatWindow = null
}
})
.also {
autoPilotToolsFloat = it
floatWindow = it
if (((attrs?.softInputMode?: 0) and LayoutParams.SOFT_INPUT_MASK_ADJUST) != 0) {
it.softInputMode(attrs!!.softInputMode)
}
}
.show()
return {
autoPilotToolsFloat?.let {
floatWindow?.let {
WarningFloat.dismiss(it.config.floatTag, false)
autoPilotToolsFloat = null
floatWindow = null
}
}
}

View File

@@ -13,10 +13,10 @@ import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.function.hmi.ui.utils.KeyBoardUtil
import com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import kotlinx.android.synthetic.main.view_auto_pilot_check.view.*
import kotlinx.android.synthetic.main.view_check_system.view.*
/**
* @author ChenFufeng
@@ -60,7 +60,9 @@ class AutoPilotAndCheckView @JvmOverloads constructor(
ToastUtils.showShort("超过最大限速值60设置失败")
}
else -> {
llSpeedPosition.background = resources.getDrawable(R.drawable.pilot_speed_bg)
keyBoardUtil?.hideKeyboard()
etInputSpeed.clearFocus()
// 设置自动驾驶速度
val isSuccess = CallerAutoPilotManager.setAutoPilotSpeed(speed)
when {
@@ -85,12 +87,16 @@ class AutoPilotAndCheckView @JvmOverloads constructor(
ivDebugPanel.setOnClickListener {
clickListener?.showDebugPanelView()
}
ivDebugFeedback.onClick {
clickListener?.showFeedbackView()
}
etInputSpeed.setOnTouchListener { v, _ ->
if (!connectStatus) {
ToastUtils.showShort("设置车速失败,请启动域控制器")
keyBoardUtil?.hideKeyboard()
return@setOnTouchListener true
} else {
llSpeedPosition.background = resources.getDrawable(R.drawable.pilot_speed_high_light_bg)
if (etInputSpeed.hasFocusable()) {
if (keyBoardUtil == null) {
keyBoardUtil = KeyBoardUtil(sKeyBoardView, etInputSpeed)
@@ -176,5 +182,6 @@ class AutoPilotAndCheckView @JvmOverloads constructor(
fun go2CheckPage()
fun onClose(v: View)
fun showDebugPanelView()
fun showFeedbackView()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -2,5 +2,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#263869" />
<corners android:radius="20px" />
<stroke android:color="#5EBFFF" android:width="2px" />
</shape>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#263869" />
<corners android:radius="20px" />
<stroke android:color="#5EBFFF" android:width="2px" />
</shape>

View File

@@ -67,8 +67,7 @@
android:background="@drawable/debug_icon_nor"
app:layout_constraintStart_toEndOf="@id/viewCheckStatus"
app:layout_constraintTop_toTopOf="@id/viewCheckStatus"
android:layout_marginStart="142px"
/>
android:layout_marginStart="142px" />
<TextView
android:id="@+id/tvDebug"
@@ -82,6 +81,27 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ivDebugPanel" />
<ImageView
android:id="@+id/ivDebugFeedback"
android:layout_width="150px"
android:layout_height="150px"
android:background="@drawable/debug_icon_feedback"
app:layout_constraintStart_toEndOf="@id/ivDebugPanel"
app:layout_constraintTop_toTopOf="@id/viewCheckStatus"
android:layout_marginStart="142px" />
<TextView
android:id="@+id/tvDebugFeedback"
android:layout_width="128px"
android:layout_height="42px"
android:layout_marginStart="740px"
android:layout_marginTop="23px"
android:text="@string/debug_panel_fb"
android:textColor="@color/color_FFA7B6F0"
android:textSize="32px"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ivDebugFeedback" />
<View
android:layout_width="14px"
android:layout_height="50px"

View File

@@ -21,6 +21,7 @@
<string name="check_vehicle_detection">车辆检测</string>
<string name="debug_panel">调试面板</string>
<string name="debug_panel_fb">反馈</string>
<string name="check_vehicle_speed_setting">车速设置</string>
<string name="check_system_operation">系统运行</string>
<string name="check_system_shut_down">关机</string>

View File

@@ -135,5 +135,8 @@ interface IMoGoAutopilotProvider : IMoGoFunctionServerProvider {
*/
fun getGlobalPath()
/**
* 域控制器是否连上了
*/
fun isConnected(): Boolean
}

View File

@@ -1,5 +1,6 @@
package com.mogo.eagle.core.function.api.devatools
import android.content.Context
import android.view.View
import com.mogo.eagle.core.data.chain.ChainLogParam
import com.mogo.eagle.core.function.api.base.IMoGoFunctionServerProvider
@@ -33,4 +34,9 @@ interface IDevaToolsProvider : IMoGoFunctionServerProvider {
* 当工控机回调时调用
*/
fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel)
/**
* 展示反馈页面
*/
fun showFeedbackWindow(ctx: Context)
}

View File

@@ -1,6 +1,7 @@
package com.mogo.eagle.core.function.api.hmi.warning
import android.view.View
import android.view.WindowManager.LayoutParams
import com.mogo.eagle.core.data.enums.WarningDirectionEnum
import com.mogo.eagle.core.data.notice.NoticeNormalData
import com.mogo.eagle.core.data.notice.NoticeTrafficStylePushData
@@ -212,7 +213,7 @@ interface IMoGoWaringProvider : IMoGoHmiViewProxy {
* @param tag: 唯一标识
* @return 触发消失时回调
*/
fun showBadCaseFloat(tag: String = "BadCaseFloat", floatView: View): () -> Unit
fun showFloatWindow(tag: String = "BadCaseFloat", floatView: View, attrs: LayoutParams?): () -> Unit
}

View File

@@ -73,6 +73,13 @@ object CallerAutoPilotManager {
providerApi?.recordPackage(type, id, duration)
}
/**
* 停止录制bag包
*/
fun stopRecord(type: Int, id: Int) {
providerApi?.stopRecord(type, id)
}
fun setEnableLog(isEnableLog: Boolean) {
providerApi?.setEnableLog(isEnableLog)
}
@@ -124,4 +131,11 @@ object CallerAutoPilotManager {
fun setControlAutopilotCarAuto(isEnable: Boolean) {
providerApi?.setControlAutopilotCarAuto(isEnable)
}
/**
* 车机与工控机是否连上了
*/
fun isConnected(): Boolean {
return providerApi?.isConnected() ?: false
}
}

View File

@@ -1,5 +1,7 @@
package com.mogo.eagle.core.function.call.devatools
import android.content.Context
import android.view.ContextMenu
import android.view.View
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.data.chain.ChainLogParam
@@ -64,4 +66,11 @@ object CallerDevaToolsManager {
fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel) {
devaToolsProviderApi?.onReceiveBadCaseRecord(record)
}
/**
* 展示反馈界面
*/
fun showFeedbackView(ctx: Context) {
devaToolsProviderApi?.showFeedbackWindow(ctx)
}
}

View File

@@ -1,6 +1,7 @@
package com.mogo.eagle.core.function.call.hmi
import android.view.View
import android.view.WindowManager.LayoutParams
import com.alibaba.android.arouter.launcher.ARouter
import com.mogo.eagle.core.data.constants.MoGoFragmentPaths
import com.mogo.eagle.core.data.enums.WarningDirectionEnum
@@ -289,10 +290,10 @@ object CallerHmiManager : CallerBase() {
}
/**
* 展示BadCase浮层
* 展示浮层
*/
fun showBadCaseFloat(tag: String = "BadCaseFloat", floatView: View): (() -> Unit)? {
return waringProviderApi?.showBadCaseFloat(tag, floatView)
fun showFloatWindow(tag: String, floatView: View, attrs: LayoutParams? = null): (() -> Unit)? {
return waringProviderApi?.showFloatWindow(tag, floatView, attrs)
}
/**

View File

@@ -1,32 +0,0 @@
package com.mogo.eagle.core.function.call.logger
import com.mogo.eagle.core.function.call.devatools.scene.Scene.Companion.scene
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
object CallerLogger {
fun i(tag: String, message: String, any: Any) {
if (scene.check(tag)) {
Logger.i(tag, message, any)
}
}
fun d(tag: String, message: String, any: Any) {
if (scene.check(tag)) {
Logger.d(tag, message, any)
}
}
fun w(tag: String, message: String, any: Any) {
if (scene.check(tag)) {
Logger.w(tag, message, any)
}
}
fun e(tag: String, message: String, any: Any) {
if (scene.check(tag)) {
Logger.e(tag, message, any)
}
}
}

View File

@@ -2,22 +2,41 @@ package com.mogo.eagle.core.utilcode.kotlin
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.text.TextUtils
import android.text.*
import android.text.style.ForegroundColorSpan
import android.util.TypedValue
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.widget.EditText
import android.widget.PopupWindow
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.IntRange
import androidx.core.view.ViewCompat
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doBeforeTextChanged
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.*
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.reminder.Reminder
import com.mogo.eagle.core.utilcode.reminder.api.impl.PopupWindowReminder
import com.mogo.eagle.core.utilcode.util.ClickUtils
import com.mogo.eagle.core.utilcode.util.R
import com.mogo.eagle.core.utilcode.util.Utils
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import java.lang.IllegalStateException
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.SECONDS
import kotlin.math.abs
val <T: View> T.lifecycleOwner: LifecycleOwner
get() = getTag(R.id.view_lifecycle_owner) as? LifecycleOwner ?: object : LifecycleOwner, LifecycleEventObserver {
@@ -64,6 +83,9 @@ val <T: View> T.lifecycleOwner: LifecycleOwner
setTag(R.id.view_lifecycle_owner, it)
}
val <T: View> T.scope
get() = lifecycleOwner.lifecycleScope
fun View.onClick(block: (View) -> Unit) {
this.setOnClickListener {
if (ClickUtils.isClickTooFrequent(this)) {
@@ -76,6 +98,9 @@ fun View.onClick(block: (View) -> Unit) {
val <T: Context> T.lifeCycleScope: LifecycleCoroutineScope
get() = (this as? LifecycleOwner)?.lifecycleScope ?: ProcessLifecycleOwner.get().lifecycleScope
val <T: Context> T.lifeCycleOwner: LifecycleOwner
get() = (this as? LifecycleOwner) ?: ProcessLifecycleOwner.get()
fun <T: View> T.observe(target: Array<Event>, block: ((event: Event) -> Unit) ?= null) {
block?.let {
this.lifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
@@ -88,6 +113,18 @@ fun <T: View> T.observe(target: Array<Event>, block: ((event: Event) -> Unit) ?=
}
}
fun <T: View> T.onDetach(block: (() -> Unit)? = null) {
block?.also {
this.lifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Event) {
if (event == ON_DESTROY) {
it.invoke()
}
}
})
}
}
fun Job.safeCancel(cause: String? = null) = try {
this.cancel(if (TextUtils.isEmpty(cause)) null else CancellationException(cause))
} catch (t: Throwable) { t.printStackTrace() }
@@ -104,8 +141,9 @@ fun <T: Any> Deferred<T>.safeCancel(cause: String? = null) = try {
this.cancel(if (TextUtils.isEmpty(cause)) null else CancellationException(cause))
} catch (t: Throwable) { t.printStackTrace() }
fun shape(@ColorInt solid: Int = Color.TRANSPARENT, @ColorInt stroke: Int = Color.TRANSPARENT, @IntRange(from = 0) strokeWidth: Int = 0, @IntRange(from = 0) radius: Int = 0, radii: FloatArray = FloatArray(8).apply { Arrays.fill(this, radius.toFloat()) }, shape: Int = GradientDrawable.RECTANGLE): Drawable {
fun shape(@ColorInt solid: Int = Color.TRANSPARENT, @ColorInt stroke: Int = Color.TRANSPARENT, @IntRange(from = 0) strokeWidth: Int = 0, @IntRange(from = 0) radius: Int = 0, radii: FloatArray = FloatArray(8).apply { Arrays.fill(this, radius.toFloat()) }, shape: Int = GradientDrawable.RECTANGLE, width: Int = 0, height: Int = 0): Drawable {
val drawable = GradientDrawable()
drawable.setSize(width, height)
drawable.shape = shape
drawable.gradientType = GradientDrawable.LINEAR_GRADIENT
drawable.setColor(solid)
@@ -115,7 +153,7 @@ fun shape(@ColorInt solid: Int = Color.TRANSPARENT, @ColorInt stroke: Int = Colo
}
fun gradient(shape: Int = GradientDrawable.RECTANGLE, @IntRange(from = 0) radius: Int = 0, radii: FloatArray = FloatArray(8).apply { Arrays.fill(this, radius.toFloat()) }, gradientType: Int = GradientDrawable.LINEAR_GRADIENT, orientation: GradientDrawable.Orientation = GradientDrawable.Orientation.TOP_BOTTOM, centerX: Float = 0.5f, centerY: Float = 0.5f, @ColorInt startColor: Int, @ColorInt centerColor: Int = startColor, @ColorInt endColor: Int): Drawable{
val drawable = GradientDrawable(orientation, intArrayOf(endColor, centerColor, startColor))
val drawable = GradientDrawable(orientation, intArrayOf(startColor, centerColor, endColor))
drawable.shape = shape
drawable.gradientType = gradientType
drawable.orientation = orientation
@@ -124,7 +162,146 @@ fun gradient(shape: Int = GradientDrawable.RECTANGLE, @IntRange(from = 0) radius
return drawable
}
fun Int.toPixels(context: Context? = null): Float {
val ctx = context ?: Utils.getApp()
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, this.toFloat(), ctx.resources.displayMetrics)
val Int.PX: Int
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, this.toFloat(), Utils.getApp().resources.displayMetrics).toInt()
val Int.SP: Int
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Utils.getApp().resources.displayMetrics).toInt()
fun <T: EditText> T.watch(@IntRange(from = 1) maxCharCount: Int, onCountChanged:((count: Int) -> Unit)? = null, onTextChanged:((editable: Editable?) -> Unit)? = null, onReachMaxCountAction:((text: T) -> Unit)? = null, onGetFocus:((text: T) -> Unit)? = null) {
doAfterTextChanged { itx ->
onTextChanged?.invoke(itx)
if (itx == null || itx.isEmpty()) {
onCountChanged?.invoke(0)
return@doAfterTextChanged
}
val length = itx.length
if (length > maxCharCount) {
text = itx.delete(maxCharCount, length)
Selection.setSelection(text, maxCharCount)
onCountChanged?.invoke(maxCharCount)
onReachMaxCountAction?.invoke(this)
} else {
onCountChanged?.invoke(length)
}
}
doBeforeTextChanged { _, _, _, _ ->
onGetFocus?.invoke(this)
}
}
fun <T: TextView> T.spannableText(parts: List<CharSequence>, colors: List<Int>) {
if (parts.isEmpty() || colors.isEmpty() || parts.size != colors.size) {
return
}
val ssb = SpannableStringBuilder()
parts.forEachIndexed { index, sequence ->
val text = SpannableString(sequence)
text.setSpan(ForegroundColorSpan(colors[index]), 0, sequence.length, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
ssb.append(text)
}
text = ssb
}
fun RecyclerView.fixGestureConflictForViews(ids: List<Int> = emptyList()) {
val fixer = GestureConflictFixer(ids)
addOnItemTouchListener(fixer)
addOnScrollListener(fixer)
}
private class GestureConflictFixer(private val ids: List<Int>) : RecyclerView.OnScrollListener(), RecyclerView.OnItemTouchListener {
private var scrollState = RecyclerView.SCROLL_STATE_IDLE
private var scrollPointerId = -1
private var initialTouchX = 0
private var initialTouchY = 0
private var dx = 0
private var dy = 0
private var intercpted = false
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
when (e.actionMasked) {
MotionEvent.ACTION_DOWN -> {
scrollPointerId = e.getPointerId(0)
initialTouchX = (e.x + 0.5f).toInt()
initialTouchY = (e.y + 0.5f).toInt()
intercpted = computeIntercepted(initialTouchX, initialTouchY, rv, ids)
}
MotionEvent.ACTION_POINTER_DOWN -> {
val actionIndex = e.actionIndex
scrollPointerId = e.getPointerId(actionIndex)
initialTouchX = (e.getX(actionIndex) + 0.5f).toInt()
initialTouchY = (e.getY(actionIndex) + 0.5f).toInt()
}
MotionEvent.ACTION_MOVE -> {
val index = e.findPointerIndex(scrollPointerId)
if (index >= 0 && scrollState != RecyclerView.SCROLL_STATE_DRAGGING) {
val x = (e.getX(index) + 0.5f).toInt()
val y = (e.getY(index) + 0.5f).toInt()
dx = x - initialTouchX
dy = y - initialTouchY
}
}
MotionEvent.ACTION_UP -> {
intercpted = false
}
}
return false
}
private fun computeIntercepted(x: Int, y: Int, rv: RecyclerView, ids: List<Int>): Boolean {
return ids.takeIf { it.isNotEmpty() }?.find {
val out = Rect()
rv.findViewById<View>(it).getGlobalVisibleRect(out)
out.contains(x, y)
}?.let { it != View.NO_ID } ?: false
}
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
val oldState = scrollState
scrollState = newState
if (oldState == RecyclerView.SCROLL_STATE_IDLE && newState == RecyclerView.SCROLL_STATE_DRAGGING) {
recyclerView.layoutManager?.let {
if (intercpted) {
recyclerView.stopScroll()
}
}
}
}
}
fun Context.toast(text: CharSequence, duration: Long = 2, unit: TimeUnit = SECONDS) {
val activity = (this as? FragmentActivity) ?: throw IllegalStateException("please use Activity to trigger toast show.")
activity.lifeCycleScope.launchWhenResumed {
val pop = PopupWindow(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT).also {
it.isOutsideTouchable = false
it.isTouchable = false
it.isFocusable = false
it.setBackgroundDrawable(shape(solid = Color.parseColor("#99000000"), radius = 32.PX))
}
val tv = TextView(this@toast)
tv.setTextColor(Color.WHITE)
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, 56.0f)
tv.setPaddingRelative(114.PX, 61.PX, 114.PX, 61.PX)
tv.text = text
pop.contentView = tv
val reminder = object : PopupWindowReminder(pop) {
override fun show() {
pop.showAtLocation(activity.window.decorView, Gravity.CENTER, 0, 0)
lifecycleOwner().lifecycleScope.launch {
delay(unit.toMillis(duration))
hide()
}
}
override fun isOverride(): Boolean = true
}
Reminder.enqueue(activity.lifeCycleOwner, reminder)
}
}

View File

@@ -2,7 +2,7 @@ package com.mogo.map;
import static com.mogo.map.marker.MarkerType.MAP_STATIC;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.map.marker.AMapMarkerWrapper;
import com.mogo.map.marker.IMogoMarker;
import com.mogo.map.marker.IMogoMarkerClickListener;
@@ -54,7 +54,7 @@ public class AMapMarkerClickHandler {
if (MarkerWrapperClickHelper.getInstance().isStaticMarker(marker.getId())){
IMogoMarker iMogoMarker = new AMapMarkerWrapper(marker,new MogoMarkerOptions());
iMogoMarker.setOwner(MAP_STATIC); //TODO 后续可能由于类型比较多需要owner匹配机制,以及控制owner细粒度
Logger.d("AMapMarkerWrapper", "traffic marker 点击回调");
CallerLogger.INSTANCE.d("AMapMarkerWrapper", "traffic marker 点击回调");
return MogoMarkersHandler.getInstance().onStaticMarkerClicked(iMogoMarker);
}
@@ -62,7 +62,7 @@ public class AMapMarkerClickHandler {
if (mogoMarkerMap.containsKey(marker.getId())) {
IMogoMarker mogoMarker = mogoMarkerMap.get(marker.getId());
final IMogoMarkerClickListener listener = mogoMarker.getOnMarkerClickListener();
Logger.d("AMapMarkerWrapper", "marker 点击回调:%s -> %s", mogoMarker, marker);
CallerLogger.INSTANCE.d("AMapMarkerWrapper", "marker 点击回调:%s -> %s", mogoMarker, marker);
if (listener != null) {
boolean result = listener.onMarkerClicked(mogoMarker);
if (result) {

View File

@@ -3,8 +3,7 @@ package com.mogo.map;
import android.content.Context;
import android.graphics.Point;
import com.mogo.eagle.core.data.traffic.TrafficData;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.map.marker.AMapInfoWindowAdapter;
import com.mogo.map.marker.AMapMarkerWrapper;
import com.mogo.map.marker.IMogoMarker;
@@ -53,7 +52,7 @@ public class AMapWrapper implements IMogoMap {
private IMogoUiSettings mUiSettings;
public AMapWrapper(MapAutoViewHelper map, MapAutoView mapView, IMogoMapUIController controller) {
Logger.i(TAG, "autoop--AMapWrapper: init" + this);
CallerLogger.INSTANCE.i(TAG, "autoop--AMapWrapper: init" + this);
this.mAMap = map;
sAMap = map;
this.mMapView = mapView;
@@ -91,7 +90,7 @@ public class AMapWrapper implements IMogoMap {
}
MarkerOptions markerOptions = ObjectUtils.fromMogo(options);
if (markerOptions == null) {
Logger.e(TAG, "marker参数为空");
CallerLogger.INSTANCE.e(TAG, "marker参数为空");
return null;
}
final IMogoMarker mogoMarker = new AMapMarkerWrapper(mAMap.addMarker(markerOptions), options);
@@ -110,7 +109,7 @@ public class AMapWrapper implements IMogoMap {
for (MessagePad.TrackedObject mogoMarkerOptions : optionsArrayList) {
MarkerSimpleData markerOptions = ObjectUtils.fromTrafficData(mogoMarkerOptions);
if (markerOptions == null) {
Logger.e(TAG, "marker参数为空");
CallerLogger.INSTANCE.e(TAG, "marker参数为空");
break;
}
markerOptionsArrayList.add(markerOptions);
@@ -259,7 +258,7 @@ public class AMapWrapper implements IMogoMap {
@Override
public void changeZoom(float zoom) {
Logger.d(TAG, "changeZoom %s", zoom);
CallerLogger.INSTANCE.d(TAG, "changeZoom %s", zoom);
if (checkAMap()) {
mAMap.setZoom((int) zoom);
}
@@ -283,7 +282,7 @@ public class AMapWrapper implements IMogoMap {
public IMogoPolyline addPolyline(MogoPolylineOptions options) {
if (checkAMap()) {
PolylineOptions polylineOptions = ObjectUtils.fromMogo(options);
Logger.d(TAG, "addPolyline %s", polylineOptions.toString());
CallerLogger.INSTANCE.d(TAG, "addPolyline %s", polylineOptions.toString());
if (polylineOptions == null) {
return null;
}
@@ -307,7 +306,7 @@ public class AMapWrapper implements IMogoMap {
mAMap = mMapView.getMapAutoViewHelper();
sAMap = mAMap;
if (mAMap == null) {
Logger.e(TAG, "自研map实例为空请检查");
CallerLogger.INSTANCE.e(TAG, "自研map实例为空请检查");
return false;
}
return true;

View File

@@ -4,7 +4,7 @@ import android.content.Context;
import android.util.Log;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.map.location.ALocationClient;
import com.mogo.map.location.IMogoLocationClient;
import com.mogo.map.search.GeocodeSearchClient;
@@ -85,6 +85,6 @@ public class CustomMapApiBuilder implements IMogoMapApiBuilder {
@Override
public void init(Context context) {
Logger.d(TAG, "init");
CallerLogger.INSTANCE.d(TAG, "init");
}
}

View File

@@ -7,7 +7,7 @@ import android.view.View;
import android.view.animation.Interpolator;
import com.mogo.eagle.core.data.map.MogoLatLng;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.map.marker.anim.OnMarkerAnimationListener;
import com.mogo.map.utils.ObjectUtils;
import com.zhidaoauto.map.sdk.open.abs.marker.MarkerAnimationListener;
@@ -427,7 +427,7 @@ public class AMapMarkerWrapper implements IMogoMarker, Observer {
mMarker.setTranslateAnimation( animation );
mMarker.startAnimation();
} catch ( Exception e ) {
Logger.e( TAG, e, "error." );
CallerLogger.INSTANCE.e( TAG, e, "error." );
}
}
@@ -495,7 +495,7 @@ public class AMapMarkerWrapper implements IMogoMarker, Observer {
mMarker.marker3DIcon( model3D );
return mMarker.getMarkeOptions().getMarkerIconName();
} catch ( Exception e ) {
Logger.e( TAG, e, "use3DResource" );
CallerLogger.INSTANCE.e( TAG, e, "use3DResource" );
}
return null;
}
@@ -506,7 +506,7 @@ public class AMapMarkerWrapper implements IMogoMarker, Observer {
mMarker.getMarkeOptions().setVrIcon( true );
mMarker.setMarkerOptions( mMarker.getMarkeOptions().setMarkerIconName( resName ) );
} catch ( Exception e ) {
Logger.e( TAG, e, "use3DResource" );
CallerLogger.INSTANCE.e( TAG, e, "use3DResource" );
}
}
@@ -516,7 +516,7 @@ public class AMapMarkerWrapper implements IMogoMarker, Observer {
mMarker.getMarkeOptions().setVrIcon( false );
mMarker.setMarkerOptions( mMarker.getMarkeOptions().setMarkerIconName( resName ) );
} catch ( Exception e ) {
Logger.e( TAG, e, "use3DResource" );
CallerLogger.INSTANCE.e( TAG, e, "use3DResource" );
}
}

View File

@@ -2,7 +2,7 @@ package com.mogo.map.search;
import android.content.Context;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.map.search.inputtips.IMogoInputtipsListener;
import com.mogo.map.search.inputtips.IMogoInputtipsSearch;
import com.mogo.map.search.inputtips.MogoTip;
@@ -60,7 +60,7 @@ public class InputtipsSearch implements IMogoInputtipsSearch, InputtipsListener
mListener.onGetInputtips(getResult(list));
}
} else {
Logger.e(TAG, "errorcode = " + i);
CallerLogger.INSTANCE.e(TAG, "errorcode = " + i);
}
}

View File

@@ -2,7 +2,7 @@ package com.mogo.map.search;
import android.content.Context;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.map.exception.MogoMapException;
import com.mogo.map.search.geo.MogoPoiItem;
import com.mogo.map.search.poisearch.IMogoPoiSearch;
@@ -111,7 +111,7 @@ public class PoiSearchClient implements IMogoPoiSearch, OnPoiSearchListener {
@Override
public void onPoiSearched( PoiSearchResult poiResult, int errorCode ) {
if ( errorCode != 0 ) {
Logger.e( TAG, "errorcode is %d", errorCode );
CallerLogger.INSTANCE.e( TAG, "errorcode is %d", errorCode );
}
if ( mListener != null ) {
mListener.onPoiSearched( ObjectUtils.fromAMap( poiResult ), errorCode );
@@ -121,7 +121,7 @@ public class PoiSearchClient implements IMogoPoiSearch, OnPoiSearchListener {
@Override
public void onPoiItemSearched( PoiItem poiItem, int errorCode ) {
if ( errorCode != 0 ) {
Logger.e( TAG, "errorcode is %d", errorCode );
CallerLogger.INSTANCE.e( TAG, "errorcode is %d", errorCode );
}
if ( mListener != null ) {
mListener.onPoiItemSearched( ObjectUtils.fromAMap( poiItem ), errorCode );

View File

@@ -2,7 +2,7 @@ package com.mogo.map.utils;
import com.mogo.cloud.commons.utils.CoordinateUtils;
import com.mogo.eagle.core.data.map.MogoLatLng;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.zhidaoauto.map.sdk.open.query.LonLatPoint;
import java.util.List;
@@ -38,13 +38,13 @@ public class PointInterpolatorUtil {
MogoLatLng current = points.get(i);
MogoLatLng next = points.get(i + 1);
float distance = CoordinateUtils.calculateLineDistance(current.lon, current.lat, next.lon, next.lat);
Logger.d(TAG, i + ": " + distance);
CallerLogger.INSTANCE.d(TAG, i + ": " + distance);
if (distance > DISTANCE_THRESHOLD) {
int inter = (int) (distance / DISTANCE_THRESHOLD) + 1;
for (int j = 1; j < inter; j++) {
double newLat = current.lat + (next.lat - current.lat) * j / inter;
double newLon = current.lon + (next.lon - current.lon) * j / inter;
Logger.d(TAG, "distance: " + distance + ", j: " + j + ", nextLat: " + next.lat + ", nextLon: " + next.lon + ", newLat: " + newLat + ", newLon: " + newLon);
CallerLogger.INSTANCE.d(TAG, "distance: " + distance + ", j: " + j + ", nextLat: " + next.lat + ", nextLon: " + next.lon + ", newLat: " + newLat + ", newLon: " + newLon);
points.add(i + 1, new MogoLatLng(newLat, newLon));
current = points.get(++i);
}