diff --git a/OCH/README.md b/OCH/README.md new file mode 100644 index 0000000000..56d1764db2 --- /dev/null +++ b/OCH/README.md @@ -0,0 +1,7 @@ +# 网约车(Online Car Hailing) + +## 小巴 + +## 出租车 + +## 无实现 \ No newline at end of file diff --git a/OCH/mogo-och-bus/.gitignore b/OCH/mogo-och-bus/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/OCH/mogo-och-bus/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/OCH/mogo-och-bus/build.gradle b/OCH/mogo-och-bus/build.gradle new file mode 100644 index 0000000000..c4d26e2410 --- /dev/null +++ b/OCH/mogo-och-bus/build.gradle @@ -0,0 +1,70 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.alibaba.arouter' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion rootProject.ext.android.compileSdkVersion + // buildToolsVersion rootProject.ext.android.buildToolsVersion + defaultConfig { + minSdkVersion rootProject.ext.android.minSdkVersion + targetSdkVersion rootProject.ext.android.targetSdkVersion + versionCode Integer.valueOf(VERSION_CODE) + versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION") + + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [AROUTER_MODULE_NAME: project.getName()] + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation rootProject.ext.dependencies.kotlinstdlibjdk7 + implementation rootProject.ext.dependencies.androidxappcompat + implementation rootProject.ext.dependencies.arouter + annotationProcessor rootProject.ext.dependencies.aroutercompiler + implementation rootProject.ext.dependencies.androidxconstraintlayout + + implementation rootProject.ext.dependencies.rxjava + implementation rootProject.ext.dependencies.rxandroid + + implementation rootProject.ext.dependencies.androidxrecyclerview + if (Boolean.valueOf(USE_MAVEN_PACKAGE)) { + implementation rootProject.ext.dependencies.mogoutils + implementation rootProject.ext.dependencies.mogocommons + implementation rootProject.ext.dependencies.modulecommon + implementation rootProject.ext.dependencies.mogo_core_data + implementation rootProject.ext.dependencies.mogo_core_function_call + }else { + implementation project(":core:mogo-core-utils") + implementation project(":foudations:mogo-commons") + implementation project(':modules:mogo-module-common') + implementation project(':core:mogo-core-data') + implementation project(':core:mogo-core-function-call') + } +} + +apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString() \ No newline at end of file diff --git a/OCH/mogo-och-bus/consumer-rules.pro b/OCH/mogo-och-bus/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/OCH/mogo-och-bus/gradle.properties b/OCH/mogo-och-bus/gradle.properties new file mode 100644 index 0000000000..dd5c44ee62 --- /dev/null +++ b/OCH/mogo-och-bus/gradle.properties @@ -0,0 +1,3 @@ +GROUP=com.mogo.och +POM_ARTIFACT_ID=och-bus +VERSION_CODE=1 diff --git a/OCH/mogo-och-bus/libs/pinyin4j-2.5.1.jar b/OCH/mogo-och-bus/libs/pinyin4j-2.5.1.jar new file mode 100644 index 0000000000..8446c53fce Binary files /dev/null and b/OCH/mogo-och-bus/libs/pinyin4j-2.5.1.jar differ diff --git a/OCH/mogo-och-bus/proguard-rules.pro b/OCH/mogo-och-bus/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/OCH/mogo-och-bus/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/AndroidManifest.xml b/OCH/mogo-och-bus/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..8f40dcf1a5 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/IMogoOCH.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/IMogoOCH.java new file mode 100644 index 0000000000..073f7fcc29 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/IMogoOCH.java @@ -0,0 +1,24 @@ +package com.mogo.och.bus; + +import androidx.annotation.IdRes; +import androidx.fragment.app.FragmentActivity; + +import com.mogo.eagle.core.function.api.base.IMoGoFunctionProvider; + +public +/** + * @author congtaowang + * @since 2021/1/15 + * + * 网约车抽象接口 + */ +interface IMogoOCH extends IMoGoFunctionProvider { + + /** + * 初始化网约车容器 + * + * @param activity + * @param containerId 容器ID + */ + void createCoverage(FragmentActivity activity, @IdRes int containerId); +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/OchBusProvider.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/OchBusProvider.java new file mode 100644 index 0000000000..4dba8c93ac --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/OchBusProvider.java @@ -0,0 +1,111 @@ +package com.mogo.och.bus; + +import android.content.Context; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; + +import com.alibaba.android.arouter.facade.annotation.Route; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.module.common.MogoApisHandler; +import com.mogo.och.bus.constant.OchBusConst; +import com.mogo.och.bus.fragment.OchBusFragment; +import com.mogo.service.statusmanager.IMogoStatusChangedListener; +import com.mogo.service.statusmanager.StatusDescriptor; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * 网约车小巴业务实现入口 + * + * @author tongchenfei + */ +@Route(path = OchBusConst.PATH) +public class OchBusProvider implements IMogoOCH { + private static final String TAG = "OchBusProvider"; + private OchBusFragment busFragment; + private int containerId; + private FragmentActivity activity; + + /** + * 进入鹰眼模式,设置手势缩放地图失效 + */ + private void stepIntoVrMode(){ + Logger.d( TAG, "进入vr模式" ); + MogoApisHandler.getInstance() + .getApis() + .getMapServiceApi() + .getMapUIController() + .openVrMode(false); + } + + @Override + public void init(Context context) { + MogoApisHandler.getInstance().getApis().getStatusManagerApi().registerStatusChangedListener("OchBus", StatusDescriptor.VR_MODE, statusChangedListener); + MogoApisHandler.getInstance().getApis().getStatusManagerApi().registerStatusChangedListener("OchBus", StatusDescriptor.TOP_VIEW, statusChangedListener); + } + + private void showFragment() { + if (busFragment == null) { + Logger.d(TAG, "准备add fragment======"); + busFragment = new OchBusFragment(); + activity.getSupportFragmentManager().beginTransaction().add(containerId, busFragment).commit(); + return; + } + Logger.d(TAG, "准备show fragment"); + activity.getSupportFragmentManager().beginTransaction().show(busFragment).commit(); + } + + private void hideFragment() { + if (busFragment != null) { + Logger.d(TAG, "准备hide fragment"); + activity.getSupportFragmentManager().beginTransaction().hide(busFragment).commit(); + } + + } + + private final IMogoStatusChangedListener statusChangedListener = (descriptor, isTrue) -> { + if (descriptor == StatusDescriptor.VR_MODE) { + // 进入vr模式默认显示网约车小巴fragment + if (isTrue) { + showFragment(); + } else { + hideFragment(); + } + } else if (MogoApisHandler.getInstance().getApis().getStatusManagerApi().isVrMode() && descriptor == StatusDescriptor.TOP_VIEW) { + // topView进行展示时推出网约车界面,但是不隐藏整个fragment + if (busFragment != null && isTrue) { + busFragment.hideOchBus(); + } + } + }; + + @Override + public void createCoverage(FragmentActivity activity, int containerId) { + + } + + @NotNull + @Override + public String getFunctionName() { + return null; + } + + @Nullable + @Override + public Fragment createCoverage(@Nullable FragmentActivity fragmentActivity, @Nullable Integer integer) { + + this.containerId = integer; + this.activity = fragmentActivity; + + UiThreadHandler.postDelayed(this::stepIntoVrMode, 5_000L ); + return null; + } + + @Override + public void onDestroy() { + + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/adapter/OchBusStationAdapter.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/adapter/OchBusStationAdapter.java new file mode 100644 index 0000000000..abaf285126 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/adapter/OchBusStationAdapter.java @@ -0,0 +1,127 @@ +package com.mogo.och.bus.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.och.bus.R; +import com.mogo.och.bus.bean.OchBusStation; +import com.mogo.och.bus.constant.OchBusConst; +import com.mogo.och.bus.view.VerticalDashLineView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Station Panel 中的车站列表adapter + * + * @author tongchenfei + */ +public class OchBusStationAdapter extends RecyclerView.Adapter { + private final Context context; + private final List stationList = new ArrayList<>(); + private int currentStation; + + public OchBusStationAdapter(Context context) { + this.context = context; + } + + public void refreshStationList(List stationList) { + this.stationList.clear(); + this.stationList.addAll(stationList); + for (int i = 0; i < stationList.size(); i++) { + OchBusStation station = stationList.get(i); + if (station.getDrivingStatus() == OchBusConst.STATION_STATUS_ARRIVING || station.getDrivingStatus() == OchBusConst.STATION_STATUS_STOPPED ) { + currentStation = i; + break; + } + } + notifyDataSetChanged(); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_och_bus_station, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { +// Logger.d("OchBusStationAdapter", "position: " + position + " currPos: " + currentStation + " station: " + stationList.get(position)); + holder.tvStationName.setText(stationList.get(position).getName()); + if (position == currentStation) { + if (currentStation == 0) { + // 在起始点 + holder.tvStationName.setTextColor(context.getResources().getColor(R.color.bus_arrived_station_name_text_color)); + holder.ivIcon.setImageResource(R.drawable.bus_icon_arrived_station); + holder.vDashBottom.setColor(context.getResources().getColor(R.color.bus_not_arrive_dash_color)); + } else { + holder.tvStationName.setTextColor(context.getResources().getColor(R.color.bus_current_station_name_text_color)); + holder.ivIcon.setImageResource(R.drawable.bus_icon_arriving_station); + holder.vDashTop.setGradient(context.getResources().getColor(R.color.bus_arriving_start_dash_color), context.getResources().getColor(R.color.bus_arriving_end_dash_color)); + holder.vDashBottom.setColor(context.getResources().getColor(R.color.bus_not_arrive_dash_color)); + } + } else if (position < currentStation) { + // 驶过 + holder.tvStationName.setTextColor(context.getResources().getColor(R.color.bus_arrived_station_name_text_color)); + holder.ivIcon.setImageResource(R.drawable.bus_icon_arrived_station); + if (position == currentStation - 1) { + holder.vDashBottom.setGradient(context.getResources().getColor(R.color.bus_leaving_start_dash_color), context.getResources().getColor(R.color.bus_leaving_end_dash_color)); + holder.vDashTop.setColor(context.getResources().getColor(R.color.bus_arrived_dash_color)); + } else { + holder.vDashTop.setColor(context.getResources().getColor(R.color.bus_arrived_dash_color)); + holder.vDashBottom.setColor(context.getResources().getColor(R.color.bus_arrived_dash_color)); + } + } else { + holder.tvStationName.setTextColor(context.getResources().getColor(R.color.bus_not_arrive_station_name_text_color)); + holder.ivIcon.setImageResource(R.drawable.bus_icon_not_arrive_station); + holder.vDashTop.setColor(context.getResources().getColor(R.color.bus_not_arrive_dash_color)); + holder.vDashBottom.setColor(context.getResources().getColor(R.color.bus_not_arrive_dash_color)); + } + + if (position == 0) { + holder.tvStationNotice.setText("起点"); + holder.tvStationNotice.setVisibility(View.VISIBLE); + holder.vDashTop.setVisibility(View.GONE); + holder.vDashBottom.setVisibility(View.VISIBLE); + } else if (position == getItemCount() - 1) { + holder.tvStationNotice.setText("终点"); + holder.tvStationNotice.setVisibility(View.VISIBLE); + holder.vDashTop.setVisibility(View.VISIBLE); + holder.vDashBottom.setVisibility(View.GONE); + } else { + holder.tvStationNotice.setVisibility(View.GONE); + holder.vDashTop.setVisibility(View.VISIBLE); + holder.vDashBottom.setVisibility(View.VISIBLE); + + } + + } + + @Override + public int getItemCount() { + return stationList.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + ImageView ivIcon; + TextView tvStationName; + TextView tvStationNotice; + VerticalDashLineView vDashBottom, vDashTop; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + ivIcon = itemView.findViewById(R.id.module_mogo_och_bus_station_icon); + tvStationName = itemView.findViewById(R.id.module_mogo_och_bus_station_name); + tvStationNotice = itemView.findViewById(R.id.module_mogo_och_bus_station_notice); + vDashTop = itemView.findViewById(R.id.module_mogo_och_bus_station_top_dash); + vDashBottom = itemView.findViewById(R.id.module_mogo_och_bus_station_bottom_dash); + } + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/CarHeartbeatReqBean.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/CarHeartbeatReqBean.java new file mode 100644 index 0000000000..c85a2d0b82 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/CarHeartbeatReqBean.java @@ -0,0 +1,26 @@ +package com.mogo.och.bus.bean; + +import com.mogo.och.bus.constant.OchBusConst; + +import java.util.UUID; + +/** + * Created on 2021/9/16 + * + * 上传车机心跳信息请求数据 + */ +public class CarHeartbeatReqBean { + public String sn; + public double lon; //经度 + public double lat; //纬度 + public String msgId; //心跳信息唯一标识 + public int interval; //上报间隔,单位秒,非必传,默认60秒 + + public CarHeartbeatReqBean(String sn, double lon, double lat) { + this.sn = sn; + this.lon = lon; + this.lat = lat; + this.msgId = UUID.randomUUID().toString(); + this.interval = (int) (OchBusConst.LOOP_PERIOD_60S / 1000); + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOperationStatusRequest.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOperationStatusRequest.java new file mode 100644 index 0000000000..fcc762be44 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOperationStatusRequest.java @@ -0,0 +1,43 @@ +package com.mogo.och.bus.bean; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.network.Utils; + +public +/** + * @author congtaowang + * @since 2021/3/22 + * + * 小巴车运营状态请求参数 + */ +class OchBusOperationStatusRequest { + + private String sn; + private double lat; + private double lon; + public OchBusOperationStatusRequest(double lon, double lat) { + this.sn = MoGoAiCloudClientConfig.getInstance().getSn(); + this.lat = lat; + this.lon = lon; + } + public void setLat(double lat) { + this.lat = lat; + } + + public void setLon(double lon) { + this.lon = lon; + } + + public String getSn() { + return sn; + } + + public double getLat() { + return lat; + } + + public double getLon() { + return lon; + } + +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOperationStatusResponse.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOperationStatusResponse.java new file mode 100644 index 0000000000..fd60cc3b4d --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOperationStatusResponse.java @@ -0,0 +1,20 @@ +package com.mogo.och.bus.bean; + +import com.mogo.eagle.core.data.BaseData; + +/** + * @author congtaowang + * @since 2021/3/22 + * + * 小巴车运营状态返回参数 + */ +public class OchBusOperationStatusResponse extends BaseData { + + public Result data; + + public static class Result { + + public int serviceStatus;//0:已收车,1:已出车 + + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOrder.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOrder.java new file mode 100644 index 0000000000..1e509dfccf --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOrder.java @@ -0,0 +1,86 @@ +package com.mogo.och.bus.bean; + +/** + * @author congtaowang + * @since 2021/3/23 + *

+ * 小巴订单 + */ +public class OchBusOrder { + + /** + * orderId number + * passengerPhone string 下单用户电话 + * startStationId integer 开始站点 + * startStationName string + * endStationId integer 结束站点 + * endStationName string + */ + + private long orderId; + private String passengerPhone; + private int startStationId;//乘客上车点 + private String startStationName; + private String endStationName; + private int endStationId;//乘客下车点 + + public void setOrderId(long orderId) { + this.orderId = orderId; + } + + public void setPassengerPhone(String passengerPhone) { + this.passengerPhone = passengerPhone; + } + + public void setStartStationId(int startStationId) { + this.startStationId = startStationId; + } + + public void setStartStationName(String startStationName) { + this.startStationName = startStationName; + } + + public void setEndStationName(String endStationName) { + this.endStationName = endStationName; + } + + public void setEndStationId(int endStationId) { + this.endStationId = endStationId; + } + + public long getOrderId() { + return orderId; + } + + public String getPassengerPhone() { + return passengerPhone; + } + + public int getStartStationId() { + return startStationId; + } + + public String getStartStationName() { + return startStationName; + } + + public String getEndStationName() { + return endStationName; + } + + public int getEndStationId() { + return endStationId; + } + + @Override + public String toString() { + return "OchBusOrder{" + + "orderId=" + orderId + + ", passengerPhone='" + passengerPhone + '\'' + + ", startStationId=" + startStationId + + ", startStationName='" + startStationName + '\'' + + ", endStationName='" + endStationName + '\'' + + ", endStationId=" + endStationId + + '}'; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOrdersResponse.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOrdersResponse.java new file mode 100644 index 0000000000..252858472b --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusOrdersResponse.java @@ -0,0 +1,23 @@ +package com.mogo.och.bus.bean; + +import com.mogo.eagle.core.data.BaseData; + +import java.util.List; + +/** + * @author: wangmingjun + * @date: 2021/10/19 + */ +public class OchBusOrdersResponse extends BaseData { + public Result data; + public static class Result{ + public List orders; + } + + @Override + public String toString() { + return "OchBusOrdersResponse{" + + "data=" + data + + '}'; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusQueryLineStationsRequest.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusQueryLineStationsRequest.java new file mode 100644 index 0000000000..fdd0d7461e --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusQueryLineStationsRequest.java @@ -0,0 +1,63 @@ +package com.mogo.och.bus.bean; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; + +public +/** + * @author congtaowang + * @since 2021/3/22 + * + * 根据车机行驶线路站点信息 + */ +class OchBusQueryLineStationsRequest { + + private String sn; + private double lat; + private double lon; + private boolean markDrivingStatus; // 默认false;true:是否需要返回站点的行驶状态,对应返回的drivingStatus + // 0 - 关闭、1 - 启动 +// public String status; + public OchBusQueryLineStationsRequest(double lon, double lat,boolean markDrivingStatus) { + this.sn = MoGoAiCloudClientConfig.getInstance().getSn(); + this.lat = lat; + this.lon = lon; + this.markDrivingStatus = markDrivingStatus; + } + + public boolean isMarkDrivingStatus() { + return markDrivingStatus; + } + + public void setMarkDrivingStatus(boolean markDrivingStatus) { + this.markDrivingStatus = markDrivingStatus; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public void setLon(double lon) { + this.lon = lon; + } + + public String getSn() { + return sn; + } + + public double getLat() { + return lat; + } + + public double getLon() { + return lon; + } + // public OchBusOperationStatusRequest shutdown() { +// status = "0"; +// return this; +// } +// +// public OchBusOperationStatusRequest launch() { +// status = "1"; +// return this; +// } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusResetDrivingLineRequest.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusResetDrivingLineRequest.java new file mode 100644 index 0000000000..4faf1980a8 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusResetDrivingLineRequest.java @@ -0,0 +1,18 @@ +package com.mogo.och.bus.bean; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.network.Utils; + +/** + * @author: wangmingjun + * @date: 2021/10/18 + */ +public class OchBusResetDrivingLineRequest { + public String sn; + public int lineId; //切换到的线路id + + public OchBusResetDrivingLineRequest(int lineId) { + sn = MoGoAiCloudClientConfig.getInstance().getSn(); + this.lineId = lineId; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusRoutesResponse.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusRoutesResponse.java new file mode 100644 index 0000000000..0b7c31b096 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusRoutesResponse.java @@ -0,0 +1,27 @@ +package com.mogo.och.bus.bean; + +import com.mogo.eagle.core.data.BaseData; + +/** + * 网约车小巴路线接口请求响应结果 + * + * @author tongchenfei + */ +public class OchBusRoutesResponse extends BaseData { + private OchBusRoutesResult data; + + public OchBusRoutesResult getResult() { + return data; + } + + public void setResult(OchBusRoutesResult data) { + this.data = data; + } + + @Override + public String toString() { + return "OchBusRoutesResponse{" + + "data=" + data + + '}'; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusRoutesResult.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusRoutesResult.java new file mode 100644 index 0000000000..c55f12b3db --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusRoutesResult.java @@ -0,0 +1,45 @@ +package com.mogo.och.bus.bean; + +import java.util.List; + +/** + * 网约车小巴路线接口返回接口数据封装 + * + * @author tongchenfei + */ +public class OchBusRoutesResult { + private List sites; + private int lineId; + private String name; + private int lineType; //线路类型,0:环形 + private String description; + private int status; + + public int getLineId() { + return lineId; + } + + public String getName() { + return name; + } + + public List getSites() { + return sites; + } + + public void setSite(List site) { + this.sites = sites; + } + + @Override + public String toString() { + return "OchBusRoutesResult{" + + "sites=" + sites + + ", lineId=" + lineId + + ", name='" + name + '\'' + + ", lineType=" + lineType + + ", description='" + description + '\'' + + ", status=" + status + + '}'; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusStation.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusStation.java new file mode 100644 index 0000000000..e70d321a40 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusStation.java @@ -0,0 +1,152 @@ +package com.mogo.och.bus.bean; + +/** + * 单个网约车小巴车站信息 + * + * @author tongchenfei + */ +public class OchBusStation { +// private int lineId; +// private int siteId; +// private String siteName; +// private String cityCode; +// private String areaCode; +// private String areaName; +// private double lat; +// private double lon; +// private String siteDesc; +// private int siteState; +// private int isCurrentSite;// @see OchBusConst 是否是当前站 1:是 2:下一站 0:普通站 +// private int siteColor; +// private String peoples; +// private int ifStop; // 是否需要停靠、1需要、0不需要 + + + private String name; + private String description; + private String cityCode; + private double lon; //高精坐标 + private double lat; //高精坐标 + private int businessType; //站点类型,9:taxi,10:bus + private int status; + private int siteId; + private int seq; + private int drivingStatus;//行驶信息,0初始值;1已经过;2当前站;3未到站 + private int ifStop = 1; // 是否需要停靠、1需要、0不需要 // TODO: 2021/10/19 原来站点里有设计是否需要停靠字段,现设计暂无,默认都需要停靠 + private boolean leaving; + + public void setName(String name) { + this.name = name; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + public void setLon(double lon) { + this.lon = lon; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public void setBusinessType(int businessType) { + this.businessType = businessType; + } + + public void setStatus(int status) { + this.status = status; + } + + public void setSiteId(int siteId) { + this.siteId = siteId; + } + + public void setSeq(int seq) { + this.seq = seq; + } + + public void setDrivingStatus(int drivingStatus) { + this.drivingStatus = drivingStatus; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public String getCityCode() { + return cityCode; + } + + + public int getBusinessType() { + return businessType; + } + + public int getStatus() { + return status; + } + + public int getSiteId() { + return siteId; + } + + public int getSeq() { + return seq; + } + + public int getDrivingStatus() { + return drivingStatus; + } + + public double getLon() { + return lon; + } + + public double getLat() { + return lat; + } + + public void setIfStop(int ifStop) { + this.ifStop = ifStop; + } + + public int getIfStop() { + return ifStop; + } + + public void setLeaving(boolean leaving) { + this.leaving = leaving; + } + + public boolean isLeaving() { + return leaving; + } + + @Override + public String toString() { + return "OchBusStation{" + + "name='" + name + '\'' + + ", description='" + description + '\'' + + ", cityCode='" + cityCode + '\'' + + ", lon=" + lon + + ", lat=" + lat + + ", businessType=" + businessType + + ", status=" + status + + ", siteId=" + siteId + + ", seq=" + seq + + ", drivingStatus=" + drivingStatus + + ", ifStop=" + ifStop + + ", leaving=" + leaving + + '}'; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusUpdateSiteStatusRequest.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusUpdateSiteStatusRequest.java new file mode 100644 index 0000000000..ed5923c905 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/OchBusUpdateSiteStatusRequest.java @@ -0,0 +1,27 @@ +package com.mogo.och.bus.bean; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.network.Utils; + +/** + * @author congtaowang + * @since 2021/3/22 + * + * 小巴车运营状态请求参数 + */ +public class OchBusUpdateSiteStatusRequest { + + public String sn; + public int seq;//站点序号 + public int siteId;//站点id + public double lon; + public double lat; + + public OchBusUpdateSiteStatusRequest(int seq, int siteId, double lon, double lat) { + this.sn = MoGoAiCloudClientConfig.getInstance().getSn(); + this.seq = seq; + this.siteId = siteId; + this.lon = lon; + this.lat = lat; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryLeaveAwayPassengersRequest.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryLeaveAwayPassengersRequest.java new file mode 100644 index 0000000000..9c50552d11 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryLeaveAwayPassengersRequest.java @@ -0,0 +1,37 @@ +package com.mogo.och.bus.bean; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.network.Utils; + +/** + * 查询下车乘客请求参数 + * + * @author tongchenfei + */ +public class QueryLeaveAwayPassengersRequest { + private String sn; + private int seq; //站点在线路中的序号 + private int siteId; //站点id + + public QueryLeaveAwayPassengersRequest(int seq, int siteId) { + this.sn = MoGoAiCloudClientConfig.getInstance().getSn(); + this.seq = seq; + this.siteId = siteId; + } + + public void setSeq(int seq) { + this.seq = seq; + } + + public void setSiteId(int siteId) { + this.siteId = siteId; + } + + public int getSeq() { + return seq; + } + + public int getSiteId() { + return siteId; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryLeaveAwayPassengersResponse.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryLeaveAwayPassengersResponse.java new file mode 100644 index 0000000000..1a38e7e2eb --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryLeaveAwayPassengersResponse.java @@ -0,0 +1,60 @@ +package com.mogo.och.bus.bean; + +import com.mogo.eagle.core.data.BaseData; + +import java.util.List; + +public +/** + * @author congtaowang + * @since 2021/3/26 + * + * 到站查询下车乘客 + */ +class QueryLeaveAwayPassengersResponse extends BaseData { + + public Result data; + + public static class Result { + + public List< LeaveAwayPassenger > orders; + } + + public static class LeaveAwayPassenger { + /** + * orderId: 订单id + * orderStatus: 订单状态 + * orderType:订单类型:0及时,1预约 + * bookingTime:预计用车时间 + * businessType:订单运营类型 9:taxi,10:bus + * startSiteId: 起点站点id + * userPhone: 乘客联系方式 + * startSitePoint:开始站点坐标 + * startSiteAddr:开始地址 + * endSiteId:结束站点id + * endSitePoint:结束站点坐标 + * carNumber:车牌号 + * createTime: 创建时间 + * startTime:开始时间 + * startSiteGcjPoint:高精坐标 + * endSiteGcjPoint: + */ +//todo 目前是需要乘客电话来通知乘客下车 目前后台没有乘客信息userPhone + public long orderId; + public int orderStatus; + public int orderType; + public long bookingTime; + public int businessType; + public int startSiteId; + public String passengerPhone; + public List startSitePoint; + public String startSiteAddr; + public int endSiteId; + public List endSitePoint; + public String carNumber; + public long createTime; + public long startTime; + public List< Double > startSiteGcjPoint; + public List< Double > endSiteGcjPoint; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryOchBusOperationStatusRequest.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryOchBusOperationStatusRequest.java new file mode 100644 index 0000000000..ceaf72c7f8 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/bean/QueryOchBusOperationStatusRequest.java @@ -0,0 +1,21 @@ +package com.mogo.och.bus.bean; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.commons.network.Utils; + +public +/** + * @author congtaowang + * @since 2021/3/22 + * + * 小巴车运营状态请求参数 + */ +class QueryOchBusOperationStatusRequest { + + public String sn; + + + public QueryOchBusOperationStatusRequest() { + this.sn = MoGoAiCloudClientConfig.getInstance().getSn(); + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/CarOperationStatusCallback.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/CarOperationStatusCallback.java new file mode 100644 index 0000000000..0e9cd198da --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/CarOperationStatusCallback.java @@ -0,0 +1,9 @@ +package com.mogo.och.bus.callback; + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +public interface CarOperationStatusCallback { + void changeOperationStatus(boolean changeStatus); +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/IOCHBusControllerStatusCallback.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/IOCHBusControllerStatusCallback.java new file mode 100644 index 0000000000..1e7bd30279 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/IOCHBusControllerStatusCallback.java @@ -0,0 +1,17 @@ +package com.mogo.och.bus.callback; + +import android.location.Location; + +/** + * Created on 2021/9/10 + * + * Model->Presenter回调:状态控制器监听(accOn、adas ui show、voice ui show、push ui show、v2x ui show等等) + */ +public interface IOCHBusControllerStatusCallback { + // 是否vr map模式 + void onVRModeChanged(boolean isVRMode); + // 自车定位 + void onCarLocationChanged(Location location); + //开始开启自动驾驶 + void startOpenAutopilot(); +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/RefreshBusStationsCallback.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/RefreshBusStationsCallback.java new file mode 100644 index 0000000000..bc59a7ba79 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/RefreshBusStationsCallback.java @@ -0,0 +1,13 @@ +package com.mogo.och.bus.callback; + +import com.mogo.och.bus.bean.OchBusStation; + +import java.util.List; + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +public interface RefreshBusStationsCallback { + void refreshBusStations(List stationList, int currentStation, int nextStation,boolean isArrived); +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/SlidePannelHideCallback.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/SlidePannelHideCallback.java new file mode 100644 index 0000000000..11dd2f0d36 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/callback/SlidePannelHideCallback.java @@ -0,0 +1,9 @@ +package com.mogo.och.bus.callback; + +/** + * @author: wangmingjun + * @date: 2021/10/22 + */ +public interface SlidePannelHideCallback { + void hideSlidePanel(); +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/constant/OchBusConst.kt b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/constant/OchBusConst.kt new file mode 100644 index 0000000000..a85ea7ae3f --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/constant/OchBusConst.kt @@ -0,0 +1,49 @@ +package com.mogo.och.bus.constant + +import com.mogo.commons.debug.DebugConfig + +/** + * Created on 2021/12/6 + */ +class OchBusConst { + companion object { + + private const val BASE_URL_OCH_DEV = "http://tech-dev.zhidaohulian.com" + private const val BASE_URL_OCH_QA = "https://tech-qa.zhidaohulian.com" + private const val BASE_URL_OCH_RELEASE = "https://tech.zhidaohulian.com" + + @JvmStatic + fun getBaseUrl(): String { + return when (DebugConfig.getNetMode()) { + DebugConfig.NET_MODE_DEV, DebugConfig.NET_MODE_DEMO -> BASE_URL_OCH_DEV + DebugConfig.NET_MODE_QA -> BASE_URL_OCH_QA + DebugConfig.NET_MODE_RELEASE -> BASE_URL_OCH_RELEASE + else -> BASE_URL_OCH_RELEASE + } + } + + // OCH arouter 路由path + const val PATH = "/och/api" + + // 测试用的广播 + const val BROADCAST_TEST_BUS_CONTROL_TYPE_EXTRA_KEY = "sceneType" + // 无状态 + const val STATION_STATUS_IDLE = 0 + // 已过站(历史站) + const val STATION_STATUS_LEAVING = 1 + // 到站(当前站) + const val STATION_STATUS_STOPPED = 2 + // 未到站(未到站) + const val STATION_STATUS_ARRIVING = 3 + + // 上报心跳轮询ms + const val LOOP_PERIOD_60S = 60 * 1000L + const val LOOP_PERIOD_1S = 1 * 1000L + const val LOOP_DELAY = 100L + + //起点UUID + const val BUS_START_MAP_MAKER = "bus_start_map_maker"; + //终点UUID + const val BUS_END_MAP_MAKER = "bus_end_map_maker"; + } +} \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java new file mode 100644 index 0000000000..cf9f317208 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java @@ -0,0 +1,442 @@ +package com.mogo.och.bus.fragment; + +import android.animation.ObjectAnimator; +import android.content.Intent; +import android.graphics.Color; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.constraintlayout.widget.Group; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.debug.DebugConfig; +import com.mogo.commons.mvp.IView; +import com.mogo.commons.mvp.MvpFragment; +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.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.map.listener.IMogoMapListener; +import com.mogo.map.uicontroller.VisualAngleMode; +import com.mogo.module.common.MogoApisHandler; +import com.mogo.module.common.constants.DataTypes; +import com.mogo.module.common.view.OnPreventFastClickListener; +import com.mogo.och.bus.R; +import com.mogo.och.bus.view.BusArcView; +import com.mogo.och.bus.view.SlidePanelView; + +/** + * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况 + *

+ * 部分业务放在了此处处理 + * + * @author tongchenfei + */ +public abstract class BaseOchBusTabFragment> extends MvpFragment implements IMogoMapListener { + + private static final String TAG = "BaseOchFragment"; + + protected SlidePanelView slidePanelView; + private RelativeLayout ctvAutopilotStatus; + private ImageView ctvAutopilotStatusIv; + private TextView ctvAutopilotStatusTv; + protected TextView tvOperationStatus; + protected LinearLayout mSettingBtn; + public boolean isOperationStatus;//false-收车,true-出车 + private FrameLayout flStationPanelContainer; + private Group groupTestPanel; + private FrameLayout flSpeed; + private BusArcView mouduleArc; + + public static final String TYPE_ENTRANCE = "entrance"; + + //远景和中景的切换 + private ImageView mSwitchMapModeImage; + private FrameLayout mSwitchMapModeLayout; + private TextView mSwitchText; + + private ObjectAnimator autopilotLoadingAnimator; + /** + * 滑动按钮触发的事件 + */ + private final SlidePanelView.OnSlidePanelMoveToEndListener onSlideToEndListener = () -> { + // 此处做一个代理,处理一下共有情况 + if (getSlidePanelOnEndListener() != null) { + getSlidePanelOnEndListener().moveToEnd(); + } + }; + + @Override + protected int getLayoutId() { + return R.layout.bus_base_fragment; + } + + private View panelView; + + @Override + protected void initViews() { + groupTestPanel = findViewById(R.id.groupTestPanel); + slidePanelView = findViewById(R.id.module_mogo_och_slide_panel); + ctvAutopilotStatus = findViewById(R.id.module_mogo_och_autopilot_status); + ctvAutopilotStatusIv = findViewById(R.id.bus_autopilot_btn_iv); + ctvAutopilotStatusTv = findViewById(R.id.bus_autopolot_btn_tv); + flStationPanelContainer = findViewById(R.id.module_mogo_och_station_panel_container); + + tvOperationStatus = findViewById(R.id.module_mogo_och_operation_status); + + flSpeed = (FrameLayout) findViewById(R.id.fl_speed); + mouduleArc = (BusArcView) findViewById(R.id.bus_arc); + + panelView = LayoutInflater.from(getContext()).inflate(getStationPanelViewId(), flStationPanelContainer); + slidePanelView.setOnSlidePanelMoveToEndListener(onSlideToEndListener); + + mSwitchMapModeLayout = findViewById(R.id.bus_switch_model_layout); + mSwitchMapModeImage = findViewById(R.id.bus_switch_model_icon); + mSwitchText = findViewById(R.id.bus_switch_model_text); + + mSwitchMapModeLayout.setOnClickListener(new OnPreventFastClickListener(){ + + @Override + public void onClickImpl(View v) { + //切换地图的远近视图 + if (MogoApisHandler.getInstance().getApis().getMapServiceApi().getMapUIController().getCurrentMapVisualAngle().isLongSight()) { + MogoApisHandler.getInstance().getApis().getMapServiceApi().getMarkerManager(AbsMogoApplication.getApp()).visibleAllMarkers(); + MogoApisHandler.getInstance().getApis().getMapServiceApi() + .getMapUIController().changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null); + mSwitchText.setText(R.string.bus_map_model_normal); + } else if (MogoApisHandler.getInstance().getApis().getMapServiceApi().getMapUIController().getCurrentMapVisualAngle().isMediumSight()) { + MogoApisHandler.getInstance().getApis().getMapServiceApi().getMarkerManager(AbsMogoApplication.getApp()).inVisibleWithoutMarkers(DataTypes.TYPE_MARKER_ADAS); + MogoApisHandler.getInstance().getApis().getMapServiceApi() + .getMapUIController().changeMapVisualAngle(VisualAngleMode.MODE_LONG_SIGHT, null); + mSwitchText.setText(R.string.bus_map_model_faster); + } + } + }); + + if (DebugConfig.isDebug()) { + mouduleArc.setLongClickable(true); + mouduleArc.setOnLongClickListener(v -> { + Log.d(TAG,"长按显示状态工具栏"); + Intent intent = new Intent(); + intent.putExtra("oper", 52); + MogoApisHandler.getInstance().getApis().getIntentManagerApi().invoke("com.mogo.mock", intent); + return true; + }); + } + initListener(); + ctvAutopilotStatus.setOnClickListener(v -> { + // 如果能自动驾驶,就自动驾驶,不能就提示 +// if (MogoApisHandler.getInstance().getApis().getAdasControllerApi().getAutopilotStatus() == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE){ +// return; +// } +// if (autopilotLoadingAnimator != null){ +// TipToast.shortTip("正在开启自动驾驶。。。"); +// return; +// } + restartAutopilot(); + }); + + // debug下调用测试面板 + if (DebugConfig.isDebug()) { + ctvAutopilotStatus.setOnLongClickListener(v -> { + if (groupTestPanel.getVisibility() == View.VISIBLE) { + groupTestPanel.setVisibility(View.GONE); + } else { + groupTestPanel.setVisibility(View.VISIBLE); + } + return true; + }); + } + onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState(),false); + // 模拟 不可自动驾驶,目前场景是刚开机,adas还未和工控机连接 + findViewById(R.id.btnAutopilotDisable).setOnClickListener(view -> +// MogoApisHandler.getInstance().getApis() +// .getAdasControllerApi() +// .mockOchStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE, "不能使用") + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE) + ); + + // 模拟 可自动驾驶,工控机连接正常,且处于人工干预状态 + findViewById(R.id.btnAutopilotEnable).setOnClickListener(view -> +// MogoApisHandler.getInstance().getApis() +// .getAdasControllerApi() +// .mockOchStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE, "能使用") + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE) + ); + + // 模拟 自动驾驶能力,自动驾驶中,可能是停车,可能是行进,但是是机器在处理车的前进后退,不是人 + findViewById(R.id.btnAutopilotRunning).setOnClickListener(view -> +// MogoApisHandler.getInstance().getApis() +// .getAdasControllerApi() +// .mockOchStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING, "Running") + debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) + ); + + // 模拟 自动驾驶网约车回调数据 + findViewById(R.id.btnAutopilotArrive).setOnClickListener(view -> +// MogoApisHandler.getInstance().getApis() +// .getAdasControllerApi().mockOchStatus(-1, "Arrived") + debugArrivedStation() + ); + + tvOperationStatus.setOnClickListener(view -> { + onChangeOperationStatus(); + }); + + mSettingBtn = findViewById(R.id.module_mogo_och_setting_layout); + mSettingBtn.setOnClickListener(v -> { + // TODO: 2021/12/9 + CallerHmiManager.INSTANCE.showToolsView(); + }); + } + + /** + * 测试到站 + */ + protected abstract void debugArrivedStation(); + + private void initListener() { + MogoApisHandler.getInstance().getApis().getRegisterCenterApi().registerMogoMapListener(TYPE_ENTRANCE, this); + } + + protected void onChangeOperationStatus() { + + } + + + /** + * 展示滑动按钮 + * + * @param text 指定的文字 + */ + public void showSlidePanle(String text) { + if (isOperationStatus) { + getActivity().runOnUiThread(() -> { + slidePanelView.setText(text); + slidePanelView.setVisibility(View.VISIBLE); + }); + } + } + + /** + * 隐藏滑动按钮 + */ + public void hideSlidePanel() { + getActivity().runOnUiThread(() -> { + slidePanelView.setVisibility(View.GONE); + }); + } + + public void showNotice(String notice) { + getActivity().runOnUiThread(() -> { + AIAssist.getInstance(getContext()).speakTTSVoice(notice); + }); + } + + /** + * 改变自动驾驶状态 + * @param autopilotStatus 0:不可用 1:可用状态 2:自动驾驶中 + */ + public void onAutopilotStatusChanged(int autopilotStatus,boolean isAnimateRunning) { + getActivity().runOnUiThread(() -> { +// ctvAutopilotStatus.setChecked(isInAutopilot); + changeAutopilotBtnView(autopilotStatus,isAnimateRunning); + }); + } + + private void changeAutopilotBtnView(int autopilotStatus,boolean isAnimateRunning) { + Logger.d( TAG, "onStateChangeChangeAutopilotBtnView: " + autopilotStatus +"isAnimateRunning = "+isAnimateRunning); + if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE + == autopilotStatus) {//0不可用 + if (isAnimateRunning){ + stopAutopilotAnimation(); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_wrong_autopilot_icon); + ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatusTv.setText(getResources().getString(R.string.bus_loading_autopilot_failure_tv)); + ctvAutopilotStatus.setFocusableInTouchMode(false); + ctvAutopilotStatus.setSelected(false); + } + UiThreadHandler.postDelayed(new Runnable() { + @Override + public void run() { + ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.bus_autopilot_text_color_disable)); + ctvAutopilotStatusTv.setText(getResources().getString(R.string.bus_loading_autopilot_runnig_tv)); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon); + ctvAutopilotStatus.setSelected(false); + ctvAutopilotStatus.setFocusableInTouchMode(true); +// ctvAutopilotStatus.setPressed(false); + } + },1000); + + }else if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE + == autopilotStatus){//1可用 + if (isAnimateRunning){ + return; + } + ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatusTv.setText(getResources().getString(R.string.bus_loading_autopilot_runnig_tv)); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_ic_autopilot); + ctvAutopilotStatus.setSelected(false); + ctvAutopilotStatus.setFocusableInTouchMode(true); +// ctvAutopilotStatus.setPressed(true); + }else if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING + == autopilotStatus){//2 running + if (isAnimateRunning){ + stopAutopilotAnimation(); + } + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_right_autopilot_icon); + ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatusTv.setText(getResources().getString(R.string.bus_loading_autopilot_success_tv)); + ctvAutopilotStatus.setSelected(false); + ctvAutopilotStatus.setFocusableInTouchMode(false); + UiThreadHandler.postDelayed(new Runnable() { + @Override + public void run() { + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_ic_autopilot); + ctvAutopilotStatusTv.setText(getResources().getString(R.string.bus_loading_autopilot_runnig_tv)); + ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatus.setSelected(true); + ctvAutopilotStatus.setFocusableInTouchMode(true); +// ctvAutopilotStatus.setPressed(false); + } + },1000); + } + } + + /** + * 隐藏【自动驾驶】按钮 + */ + public void hideAutopilotBiz() { + getActivity().runOnUiThread(() -> { +// ctvAutopilotStatus.setVisibility(View.GONE); +// slidePanelView.setVisibility(View.GONE); + }); + } + + /** + * 展示【自动驾驶】按钮 + */ + public void showAutopilotBiz() { + getActivity().runOnUiThread(() -> { + ctvAutopilotStatus.setVisibility(View.VISIBLE); + if (isOperationStatus) { + slidePanelView.setVisibility(View.VISIBLE); + } else { + slidePanelView.setVisibility(View.GONE); + } + }); + } + + public void hidPanel(){ + getActivity().runOnUiThread(()->{ + flStationPanelContainer.setVisibility(View.GONE); + }); + } + + public void showPanel(){ + getActivity().runOnUiThread(()->{ + flStationPanelContainer.setVisibility(View.VISIBLE); + }); + } + + public View getPanelView() { + return panelView; + } + + public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() { + return null; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + } + + /** + * 获取站点面板view,在{@link #initViews()}时候添加到container中 + * + * @return 站点面板view + */ + public abstract int getStationPanelViewId(); + + /** + * 重新开启自动驾驶 + */ + public abstract void restartAutopilot(); + + /** + * 模拟自动驾驶返回状态 + * @param status + */ + public abstract void debugAutoPilotStatus(int status); + + /** + * 开启自动驾驶中间动画 + */ + public void startAutopilotAnimation() { +// if (MogoApisHandler.getInstance().getApis().getAdasControllerApi().getAutopilotStatus() == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE){ + ctvAutopilotStatusTv.setText(getResources().getString(R.string.bus_loading_autopilot_tv)); + ctvAutopilotStatusTv.setTextColor(getResources().getColor(R.color.bus_autopilot_text_color_normal)); + ctvAutopilotStatus.setSelected(false); + ctvAutopilotStatus.setFocusableInTouchMode(true); + ctvAutopilotStatusIv.setImageResource(R.drawable.bus_loading_autopilot_icon); + if (autopilotLoadingAnimator == null){ + autopilotLoadingAnimator = ObjectAnimator.ofFloat(ctvAutopilotStatusIv,"rotation", 0f,360f); + autopilotLoadingAnimator.setInterpolator(new LinearInterpolator()); + autopilotLoadingAnimator.setRepeatCount(-1);//无限循环 + autopilotLoadingAnimator.setDuration(1000);//设置持续时间 + } + autopilotLoadingAnimator.start();//动画开始 + // autopilotLoadingAnimator.setStartDelay(500);//循环开始延迟 + +// } + } + /** + * 停止自动驾驶中间动画 + */ + public void stopAutopilotAnimation() { + if (autopilotLoadingAnimator != null){ + autopilotLoadingAnimator.end(); + ctvAutopilotStatusIv.clearAnimation(); + autopilotLoadingAnimator = null; + } + } + + /** + * 迈速表实时更新 + * @param newSpeed + */ + public void updateSpeedView(float newSpeed){ + int speed = (int) (newSpeed * 3.6F); + mouduleArc.setArcColor(Color.parseColor(speed > 60 ? "#DB3137" : "#3E77F6")); + mouduleArc.setValues(speed); + flSpeed.setBackgroundResource(speed > 60 ? R.drawable.bus_yi_biao_pan_bg_speeding : R.drawable.bus_yi_biao_pan_bg_nor); + } + + @Override + public void onDestroy() { + super.onDestroy(); + MogoApisHandler.getInstance().getApis().getRegisterCenterApi().unregisterMogoMapListener(TYPE_ENTRANCE); + } + + @Override + public void onMapVisualAngleChanged(VisualAngleMode visualAngleMode) { + if (visualAngleMode.isMediumSight()) { + mSwitchMapModeLayout.setVisibility(View.VISIBLE); + } else if (visualAngleMode.isLongSight()) { + mSwitchMapModeLayout.setVisibility(View.VISIBLE); + } else if (visualAngleMode.isCloseSight()) { + mSwitchMapModeLayout.setVisibility(View.GONE); + } + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/OchBusFragment.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/OchBusFragment.java new file mode 100644 index 0000000000..9673c91ce4 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/OchBusFragment.java @@ -0,0 +1,319 @@ +package com.mogo.och.bus.fragment; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.debug.DebugConfig; +import com.mogo.commons.voice.AIAssist; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.mogo.toast.TipToast; +import com.mogo.map.marker.MogoMarkerOptions; +import com.mogo.module.common.MogoApisHandler; +import com.mogo.och.bus.R; +import com.mogo.och.bus.bean.OchBusStation; +import com.mogo.och.bus.constant.OchBusConst; +import com.mogo.och.bus.presenter.OchBusPresenter; +import com.mogo.och.bus.view.SlidePanelView; + +import java.util.List; + + +/** + * 网约车小巴界面 + * + * @author tongchenfei + */ +public class OchBusFragment extends BaseOchBusTabFragment< OchBusFragment, OchBusPresenter > implements SlidePanelView.OnSlidePanelMoveToEndListener { + private static final String TAG = "OchBusFragment"; + + private TextView mCurrentStationName; + private TextView mStartStationFlag; + private TextView mNextStationName; + private TextView mEndStationFlag; + private TextView mDebugArrive; + + private View mBus; + + + @Override + public String getTagName() { + return "OchBusFragment"; + } + + @Override + protected void initViews() { + super.initViews(); + mBus = findViewById( R.id.module_och_bus_tag ); + mCurrentStationName = findViewById( R.id.module_och_bus_current_station ); + mStartStationFlag = findViewById( R.id.module_och_bus_start_station_tag ); + mNextStationName = findViewById( R.id.module_och_bus_order_end_station ); + mEndStationFlag = findViewById( R.id.module_och_bus_end_station_tag ); + + mDebugArrive = findViewById(R.id.module_och_bus_arrive_station); + + if ( DebugConfig.isDebug() ) { + mBus.setOnClickListener( view -> { + TipToast.shortTip( "重置了车站状态" ); + mPresenter.queryBusRoutes(); + } ); + + mBus.setOnLongClickListener( view -> { + getActivity().finish(); + return true; + } ); + + } + mCurrentStationName.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { +// if (DebugConfig.isDebug()){ + if (mDebugArrive.getVisibility() == View.VISIBLE){ + mDebugArrive.setVisibility(View.GONE); + }else { + mDebugArrive.setVisibility(View.VISIBLE); + } +// } + return false; + } + }); + + findViewById(R.id.module_och_bus_arrive_station).setOnClickListener(view ->{ //到站 + mPresenter.onAutopilotArriveAtStation(null); + }); + + Logger.d( TAG, "initView: " + CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState()); + // 初始化的时候设置 UI 按钮状态 + switch ( CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() ) { + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE: + hideAutopilotBiz(); + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE: + showAutopilotBiz(); + onAutopilotStatusChanged( IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE ,false); + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING: + showAutopilotBiz(); + onAutopilotStatusChanged( IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING ,false); + break; + default: + break; + } + } + + @Override + protected void debugArrivedStation() { + mPresenter.onAutopilotArriveAtStation(null); + } + + @NonNull + @Override + protected OchBusPresenter createPresenter() { + return new OchBusPresenter( this ); + } + + @Override + public void onResume() { + super.onResume(); + } + + /** + * 根据站点列表信息刷新车站面板,滑块面板 + * + * @param stationList 车站列表信息 + * @param currentStation 当前站点 + * @param nextStation 下个站点 + */ + public void refreshBusStations( List< OchBusStation > stationList, int currentStation, int nextStation ,boolean isArrived) { + if ( getActivity() == null ) { + return; + } + getActivity().runOnUiThread( () -> { + if ( stationList == null ) { + // 获取小巴数据失败 + return; + } + + // 渲染小巴路线数据 + renderCurrentStationStatus( stationList, currentStation, nextStation ,isArrived); + } ); + } + + /** + * 重新刷新站点信息 + */ + private void renderCurrentStationStatus( List< OchBusStation > stationList, int currentStation, int nextStation ,boolean isArrived) { + Log.d("MapMaker= ","currentStation="+currentStation+",nextStation="+nextStation+"isArrived="+isArrived); + String currentStationName = null; + String nextStationName = null; + int startStationFlagVisibility = View.INVISIBLE; + int endStationFlagVisibility = View.INVISIBLE; + + boolean isArriveEndStation = false; + boolean isArriveAtStation = false; + boolean isArriveAtStartStation = false; + + // 获取当前站点的名称 + currentStationName = stationList.get( currentStation ).getName(); + + OchBusStation startStation = stationList.get(0); + OchBusStation endStation = stationList.get(stationList.size() - 1); + + // 是否到达起点 + if ( currentStation == 0 ) { + startStationFlagVisibility = View.VISIBLE; + isArriveAtStartStation = true; + mStartStationFlag.setText( "始" ); +// Log.d("MapMaker= ","起点="); + setOrRemoveMapMaker(true, OchBusConst.BUS_START_MAP_MAKER,startStation.getLat(),startStation.getLon(),R.drawable.icon_station_start_end); + setOrRemoveMapMaker(true, OchBusConst.BUS_END_MAP_MAKER,endStation.getLat(),endStation.getLon(),R.drawable.icon_station_start_end); + } else if ( currentStation > 0 && currentStation < stationList.size() - 1 ) {// 是否到达站点 +// Log.d("MapMaker= ","中间="); + isArriveAtStation = true; + setOrRemoveMapMaker(false, OchBusConst.BUS_START_MAP_MAKER,startStation.getLat(),startStation.getLon(),R.drawable.icon_station_start_end); + setOrRemoveMapMaker(true, OchBusConst.BUS_END_MAP_MAKER,endStation.getLat(),endStation.getLon(),R.drawable.icon_station_start_end); + } else if ( currentStation == stationList.size() - 1 ) {// 是否到达终点 +// Log.d("MapMaker= ","终点="); + isArriveEndStation = true; + nextStationName = "--"; + mStartStationFlag.setText( "终" ); + startStationFlagVisibility = View.VISIBLE; + endStationFlagVisibility = View.INVISIBLE; + setOrRemoveMapMaker(false, OchBusConst.BUS_START_MAP_MAKER,startStation.getLat(),startStation.getLon(),R.drawable.icon_station_start_end); + if (isArrived){ + setOrRemoveMapMaker(false, OchBusConst.BUS_END_MAP_MAKER,endStation.getLat(),endStation.getLon(),R.drawable.icon_station_start_end); + }else { + setOrRemoveMapMaker(true, OchBusConst.BUS_END_MAP_MAKER,endStation.getLat(),endStation.getLon(),R.drawable.icon_station_start_end); + } + } + + // 获取下一站点名称 + if ( nextStation > currentStation && nextStation <= stationList.size() - 1 ) { + nextStationName = stationList.get( nextStation ).getName(); + } + + // 是否到达终点 + if ( nextStation == stationList.size() - 1 ) { + endStationFlagVisibility = View.VISIBLE; + } + + // 重置滑动按钮文字 + if ( isArriveEndStation ) { + showSlidePanle( "单程结束" ); + } else if ( isArriveAtStartStation ) { + showSlidePanle( "滑动出发" ); + } else if ( isArriveAtStation ) { + showSlidePanle( "滑动出发" ); + } + + mCurrentStationName.setText( currentStationName ); + mNextStationName.setText( nextStationName ); + mStartStationFlag.setVisibility( startStationFlagVisibility ); + mEndStationFlag.setVisibility( endStationFlagVisibility ); + } + + public void hideOchBus() { +// tvNotice.setVisibility(View.GONE); + } + + @Override + public int getStationPanelViewId() { + return R.layout.fragment_och_bus; + } + + @Override + public void restartAutopilot() { + mPresenter.restartAutopilot(); + } + + @Override + public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() { + return this; + } + + @Override + public void moveToEnd() { + // 开启自动驾驶到下一站 + mPresenter.autoDriveToNextStation(false); + } + + /** + * 设置自动驾驶可用状态 + */ + public void onAutopilotEnableChange( boolean isEnable ) { + if ( isEnable ) { + showAutopilotBiz(); + } else { + hideAutopilotBiz(); + } + } + + @Override + protected void onChangeOperationStatus() { + super.onChangeOperationStatus(); + mPresenter.onChangeOperationStatus(); + } + + /** + * 修改经营状态 + * @param launch true-收车,false-出车 + */ + public void changeOperationStatus( boolean launch ) { + isOperationStatus = launch; + if ( launch ) { + // 出车的时候重制站点状态 + mPresenter.queryBusRoutes(); + tvOperationStatus.setText( "收车" ); + showSlidePanle("滑动出发"); + showPanel(); + } else { + AIAssist.getInstance(getContext()).speakTTSVoice("已收车"); + tvOperationStatus.setText("出车"); + hideSlidePanel(); + hidPanel(); + } + } + + /** + * VR模式切换 + * @param isVRMode + */ + public void onVRModeChanged(boolean isVRMode) { + if (mRootView != null) { + mRootView.setVisibility(isVRMode ? View.VISIBLE : View.GONE); + } + } + /** + * 绘制地图起点终点 + * @param isAdd + * @param uuid + * @param iconId + */ + private void setOrRemoveMapMaker(boolean isAdd, String uuid,double lat,double longi, int iconId){ + if (isAdd){ + Log.d("setMapMaker= ",uuid+"=latitude="+lat+",longitude="+longi); + MogoMarkerOptions options = new MogoMarkerOptions(); + options.anchorColor("#000000");//不设置报错,暂时随便设置个 + options.setGps(true);//使用wgs 必须设置true + options.scale(0.15f); + Bitmap bitmap = BitmapFactory.decodeResource(AbsMogoApplication.getApp().getResources(), iconId, null); + options.icon(bitmap); + options.latitude(lat); + options.longitude(longi); + MogoApisHandler.getInstance().getApis().getMapServiceApi().getMarkerManager(AbsMogoApplication.getApp()).addMarker(uuid, options); + }else { + Log.d("RemoveMapMaker=",uuid+"=latitude="+lat+",longitude="+longi); + MogoApisHandler.getInstance().getApis().getMapServiceApi().getMarkerManager(AbsMogoApplication.getApp()).removeMarkers(uuid); + } + } + public void debugAutoPilotStatus(int status){ + mPresenter.debugAutoPilotStatus(status); + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/IOchBusApiService.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/IOchBusApiService.java new file mode 100644 index 0000000000..8c0ab8181a --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/IOchBusApiService.java @@ -0,0 +1,126 @@ +package com.mogo.och.bus.net; +import com.mogo.eagle.core.data.BaseData; +import com.mogo.och.bus.bean.CarHeartbeatReqBean; +import com.mogo.och.bus.bean.OchBusOperationStatusRequest; +import com.mogo.och.bus.bean.OchBusQueryLineStationsRequest; +import com.mogo.och.bus.bean.OchBusOperationStatusResponse; +import com.mogo.och.bus.bean.OchBusOrdersResponse; +import com.mogo.och.bus.bean.OchBusRoutesResponse; +import com.mogo.och.bus.bean.QueryLeaveAwayPassengersRequest; +import com.mogo.och.bus.bean.QueryLeaveAwayPassengersResponse; +import com.mogo.och.bus.bean.OchBusResetDrivingLineRequest; +import com.mogo.och.bus.bean.OchBusUpdateSiteStatusRequest; + +import io.reactivex.Observable; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Headers; +import retrofit2.http.POST; +import retrofit2.http.Query; + +/** + * 小巴车相关接口 + * + * @author tongchenfei + *

+ * wiki: http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48970072 + */ +public interface IOchBusApiService { + + /** + * 根据车机坐标获取所在区域全部站点信息 + * + * @param request 请求参数 + * @return 接口返回数据 + */ + @Headers( {"Content-Type:application/json;charset=UTF-8"} ) + @POST( "/autopilot-car-hailing/bus/api/lineDataWithDriver/query" ) +// @POST( "/mock/268/autopilot-car-hailing/bus/api/lineDataWithDriver/query" ) + Observable< OchBusRoutesResponse > querySiteByCoordinate(@Body OchBusQueryLineStationsRequest request); + + /** + * 重置巴士路线: 点击小巴车tab 或者出车后会使用 + * + * @param request 请求参数{"destLine":1,"sn":"F803EB2046PZD00229"} 这个接口是重置bus线路的, 不是重置线路中站点的 + * @return 返回值是重置后的车站列表 + */ + @Headers( {"Content-Type:application/json;charset=UTF-8"} ) + @POST( "/autopilot-car-hailing/bus/api/drivingLine/reset" ) +// @POST( "/mock/268/autopilot-car-hailing/bus/api/drivingLine/reset" ) + Observable< OchBusRoutesResponse > debugResetStationStatus(@Body OchBusResetDrivingLineRequest request); + + /** + * 离站,通知服务器 + * @param request + * @return + */ + @Headers({"Content-Type:application/json;charset=UTF-8"}) + @POST("/autopilot-car-hailing/bus/api/driving/away") +// @POST("/mock/268/autopilot-car-hailing/bus/api/driving/away") + Observable< OchBusRoutesResponse > leaveStation(@Body OchBusUpdateSiteStatusRequest request); + + /** + * 到站 更新到站信息 + * @param request + * @return + */ + @Headers({"Content-type:application/json;charset=UTF-8"}) + @POST("/autopilot-car-hailing/bus/api/driving/attachSite") +// @POST("/mock/268/autopilot-car-hailing/bus/api/driving/attachSite") + Observable< BaseData > arriveSiteStation(@Body OchBusUpdateSiteStatusRequest request); + + + /** + * 到站查询下车乘客 + * @param request + * @return + */ + @Headers({"Content-type:application/json;charset=UTF-8"}) + @POST("/autopilot-car-hailing/bus/api/driving/siteArrivedOrders") +// @POST("/mock/268/autopilot-car-hailing/bus/api/driving/siteArrivedOrders") + Observable< QueryLeaveAwayPassengersResponse > queryStationLeaveAwayPassengers(@Body QueryLeaveAwayPassengersRequest request); + + /** + * 出车 + * @param request + * @return + */ + @Headers( {"Content-type:application/json;charset=UTF-8"} ) + @POST("/autopilot-car-hailing/bus/api/startTakeOrder") +// @POST("/mock/268/autopilot-car-hailing/bus/api/startTakeOrder") + Observable startTakeOrder(@Body OchBusOperationStatusRequest request); + + /** + * 收车 + * @param request + * @return + */ + @Headers({"Content-type:application/json;charset=UTF-8"}) + @POST("/autopilot-car-hailing/bus/api/stopTakeOrder") +// @POST("/mock/268/autopilot-car-hailing/bus/api/stopTakeOrder") + Observable stopTakeOrder(@Body OchBusOperationStatusRequest request); + + /** + * 查询小巴出车/收车状态 + * @param sn + * @return + */ + @Headers({"Content-type:application/json;charset=UTF-8"}) + @GET("/autopilot-car-hailing/bus/api/takeOrderStatus/query") +// @GET("/mock/268/autopilot-car-hailing/bus/api/takeOrderStatus/query") + Observable queryOperationStatus(@Query("sn") String sn); + + @Headers({"Content-type:application/json;charset=UTF-8"}) + @GET("/autopilot-car-hailing/bus/api/servicingOrders/query") +// @GET("/mock/268/autopilot-car-hailing/bus/api/servicingOrders/query") + Observable queryBusOrders(@Query("sn") String sn); + + /** + * 车机端上传心跳数据(只在出车状态时上传):包含高德坐标系经纬度 + * @param data + * @return + */ + @Headers( {"Content-type:application/json;charset=UTF-8"} ) + @POST( "/autopilot-car-hailing/api/v1/driver/heartbeat" ) + Observable runCarHeartbeat(@Body CarHeartbeatReqBean data); +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/OCHBusServiceManager.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/OCHBusServiceManager.java new file mode 100644 index 0000000000..b5de475b95 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/OCHBusServiceManager.java @@ -0,0 +1,238 @@ +package com.mogo.och.bus.net; + +import android.content.Context; + +import com.mogo.cloud.passport.MoGoAiCloudClientConfig; +import com.mogo.eagle.core.data.BaseData; +import com.mogo.eagle.core.network.RequestOptions; +import com.mogo.eagle.core.network.SubscribeImpl; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.module.common.MogoApisHandler; +import com.mogo.och.bus.bean.CarHeartbeatReqBean; +import com.mogo.och.bus.bean.OchBusOperationStatusRequest; +import com.mogo.och.bus.bean.OchBusOperationStatusResponse; +import com.mogo.och.bus.bean.OchBusOrdersResponse; +import com.mogo.och.bus.bean.OchBusQueryLineStationsRequest; +import com.mogo.och.bus.bean.OchBusResetDrivingLineRequest; +import com.mogo.och.bus.bean.OchBusRoutesResponse; +import com.mogo.och.bus.bean.OchBusUpdateSiteStatusRequest; +import com.mogo.och.bus.bean.QueryLeaveAwayPassengersRequest; +import com.mogo.och.bus.bean.QueryLeaveAwayPassengersResponse; +import com.mogo.och.bus.constant.OchBusConst; +import com.mogo.och.bus.presenter.OchBusOrderModel; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * @author: wangmingjun + * @date: 2021/10/20 + */ +public class OCHBusServiceManager { + private static final String TAG = OCHBusServiceManager.class.getSimpleName(); + private IOchBusApiService mService; + + private String baseUrl = OchBusConst.getBaseUrl(); + private static final class SingletonHolder { + private static final OCHBusServiceManager INSTANCE = new OCHBusServiceManager(); + } + public static OCHBusServiceManager getInstance(){ + return SingletonHolder.INSTANCE; + } + private OCHBusServiceManager(){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + + /** + * 查询小巴车线路 + * @param context + * @param callback + */ + public void queryBusRoutes(Context context,OCHServiceCallback callback) { + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + //获取当前高德坐标 + + mService.querySiteByCoordinate( new OchBusQueryLineStationsRequest(OchBusOrderModel.getInstance().mLongitude,OchBusOrderModel.getInstance().mLatitude,true)) + .subscribeOn( Schedulers.io() ).observeOn( AndroidSchedulers.mainThread() ) + .subscribe( getSubscribeImpl(context,callback,"querySiteByCoordinate")); + } + + /** + * 重置线路站点 + * @param context + * @param lineId + * @param callback + */ + public void debugResetStationStatus(Context context,int lineId,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.debugResetStationStatus(new OchBusResetDrivingLineRequest(lineId)) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context,callback,"debugResetStationStatus")); + } + + /** + * 离站上报 + * @param context + * @param seq + * @param siteId + * @param callback + */ + public void leaveStation(Context context,int seq,int siteId,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.leaveStation(new OchBusUpdateSiteStatusRequest(seq,siteId,OchBusOrderModel.getInstance().mLongitude,OchBusOrderModel.getInstance().mLatitude)) + .subscribeOn( Schedulers.io() ) + .observeOn( AndroidSchedulers.mainThread() ) + .subscribe(getSubscribeImpl(context,callback,"leaveStation")); + } + + /** + * 到站更新站点状态 + * @param context + * @param seq + * @param siteId + * @param callback + */ + public void arriveSiteStation(Context context,int seq,int siteId,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.arriveSiteStation(new OchBusUpdateSiteStatusRequest(seq,siteId,OchBusOrderModel.getInstance().mLongitude,OchBusOrderModel.getInstance().mLatitude)) + .subscribeOn( Schedulers.io() ) + .observeOn( AndroidSchedulers.mainThread() ) + .subscribe(getSubscribeImpl(context,callback,"leaveStation")); + } + + /** + * 查询下车乘客 + * @param context + * @param seq + * @param siteId + * @param callback + */ + public void queryStationLeaveAwayPassengers(Context context,int seq,int siteId,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.queryStationLeaveAwayPassengers( new QueryLeaveAwayPassengersRequest(seq,siteId)) + .subscribeOn( Schedulers.io() ) + .observeOn( AndroidSchedulers.mainThread() ) + .subscribe(getSubscribeImpl(context,callback,"queryStationLeaveAwayPassengers")); + } + + /** + * 收车 + * @param context + * @param callback + */ + public void stopTakeOrder(Context context,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.stopTakeOrder(new OchBusOperationStatusRequest(OchBusOrderModel.getInstance().mLongitude,OchBusOrderModel.getInstance().mLatitude)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context,callback,"stopTakeOrder")); + } + + /** + * 出车 + * @param context + * @param callback + */ + public void startTakeOrder(Context context,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.startTakeOrder(new OchBusOperationStatusRequest(OchBusOrderModel.getInstance().mLongitude,OchBusOrderModel.getInstance().mLatitude)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context,callback,"startTakeOrder")); + } + + /** + * 查询出车/收车状态 + * @param context + * @param callback + */ + public void queryOperationStatus(Context context,OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.queryOperationStatus(MoGoAiCloudClientConfig.getInstance().getSn()) + .subscribeOn( Schedulers.io() ) + .observeOn( AndroidSchedulers.mainThread() ) + .subscribe(getSubscribeImpl(context,callback,"queryOperationStatus")); + } + + /** + * 查询小巴车订单 + * @param context + * @param callback + */ + public void queryBusOrders(Context context, OCHServiceCallback callback){ + if (mService == null){ + mService = MogoApisHandler.getInstance().getApis().getNetworkApi().create( IOchBusApiService.class, baseUrl); + } + mService.queryBusOrders(MoGoAiCloudClientConfig.getInstance().getSn()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context,callback,"queryBusOrders")); + } + + /** + * 车机端上传心跳数据(只在出车状态时上传):包含高德坐标系经纬度 + * @param context + * @param lon + * @param lat + * @param callback + */ + public void runCarHeartbeat(Context context, double lon, double lat, + OCHServiceCallback callback) { + if ( mService == null ) { + mService = MogoApisHandler.getInstance().getApis().getNetworkApi() + .create(IOchBusApiService.class, baseUrl); + } + mService.runCarHeartbeat(new CarHeartbeatReqBean( + MoGoAiCloudClientConfig.getInstance().getSn(), lon, lat)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context, callback, "runCarHeartbeat")); + } + + private SubscribeImpl getSubscribeImpl(Context context, OCHServiceCallback callback, String apiName){ + return new SubscribeImpl(RequestOptions.create(context)){ + @Override + public void onSuccess(T o) { + super.onSuccess(o); + Logger.e(TAG,apiName + ": onSuccess() " + o.msg); + if (callback != null) { + callback.onSuccess(o); + } + } + + @Override + public void onError(String message, int code) { + super.onError(message, code); + Logger.e(TAG,apiName + ": onError() " +"msg="+ message+" code="+code); + if (callback != null) { + callback.onFail("msg="+ message+" code="+code); + } + } + + @Override + public void onError(Throwable e) { + super.onError(e); + Logger.e(TAG,apiName + ": onError() " +" e="+e.getMessage()); + if (callback != null) { + callback.onFail(e.getMessage()); + } + } + }; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/OCHServiceCallback.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/OCHServiceCallback.java new file mode 100644 index 0000000000..a243248570 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/net/OCHServiceCallback.java @@ -0,0 +1,15 @@ +package com.mogo.och.bus.net; + +/** + * @author: wangmingjun + * @date: 2021/10/20 + */ +public interface OCHServiceCallback< T >{ + void onSuccess(T o); + + void onFail(String failMsg); + + default void onError() { + + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusModelLoopManager.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusModelLoopManager.java new file mode 100644 index 0000000000..0ff9bd7ff8 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusModelLoopManager.java @@ -0,0 +1,52 @@ +package com.mogo.och.bus.presenter; + +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.och.bus.constant.OchBusConst; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * Created on 2021/11/22 + * + * 管理轮询逻辑(订单轮询、新单轮询、新单抢单结果轮询等等) + */ +public class OchBusModelLoopManager { + + private static final String TAG = OchBusModelLoopManager.class.getSimpleName(); + + private static final class SingletonHolder { + private static final OchBusModelLoopManager INSTANCE = new OchBusModelLoopManager(); + } + + public static OchBusModelLoopManager getInstance() { + return SingletonHolder.INSTANCE; + } + + private Disposable mHeartbeatDisposable; //心跳轮询 + + public void startHeartbeatLoop() { + if (mHeartbeatDisposable != null && !mHeartbeatDisposable.isDisposed()) { + return; + } + Logger.i(TAG, "startHeartbeatLoop()"); + mHeartbeatDisposable = Observable.interval(OchBusConst.LOOP_DELAY, + OchBusConst.LOOP_PERIOD_60S, TimeUnit.MILLISECONDS,Schedulers.trampoline()) + .map((aLong -> aLong + 1)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> OchBusOrderModel.getInstance().runCarHeartbeat()); + } + + public void stopHeartbeatLoop() { + if (mHeartbeatDisposable != null) { + Logger.i(TAG, "stopHeartbeatLoop()"); + mHeartbeatDisposable.dispose(); + mHeartbeatDisposable = null; + } + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusOrderModel.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusOrderModel.java new file mode 100644 index 0000000000..1cb2abe29a --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusOrderModel.java @@ -0,0 +1,799 @@ +package com.mogo.och.bus.presenter; + +import android.content.Context; +import android.location.Location; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.Log; + +import com.mogo.commons.AbsMogoApplication; +import com.mogo.commons.debug.DebugConfig; +import com.mogo.commons.voice.AIAssist; +import com.mogo.eagle.core.data.BaseData; +import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters; +import com.mogo.eagle.core.data.autopilot.AutopilotStationInfo; +import com.mogo.eagle.core.data.config.FunctionBuildConfig; +import com.mogo.eagle.core.data.map.MogoLatLng; +import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.mogo.toast.TipToast; +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.bus.bean.OchBusOperationStatusResponse; +import com.mogo.och.bus.bean.OchBusOrder; +import com.mogo.och.bus.bean.OchBusOrdersResponse; +import com.mogo.och.bus.bean.OchBusRoutesResponse; +import com.mogo.och.bus.bean.OchBusRoutesResult; +import com.mogo.och.bus.bean.OchBusStation; +import com.mogo.och.bus.bean.QueryLeaveAwayPassengersResponse; +import com.mogo.och.bus.callback.CarOperationStatusCallback; +import com.mogo.och.bus.callback.IOCHBusControllerStatusCallback; +import com.mogo.och.bus.callback.RefreshBusStationsCallback; +import com.mogo.och.bus.callback.SlidePannelHideCallback; +import com.mogo.och.bus.constant.OchBusConst; +import com.mogo.och.bus.net.OCHBusServiceManager; +import com.mogo.och.bus.net.OCHServiceCallback; +import com.mogo.och.bus.util.PinYinUtil; +import com.mogo.service.IMogoServiceApis; +import com.mogo.service.statusmanager.IMogoStatusChangedListener; +import com.mogo.service.statusmanager.StatusDescriptor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.exceptions.UndeliverableException; +import io.reactivex.functions.Consumer; +import io.reactivex.plugins.RxJavaPlugins; +import io.reactivex.schedulers.Schedulers; +import static com.mogo.och.bus.constant.OchBusConst.STATION_STATUS_STOPPED; + +/** + * @author congtaowang + * @since 2021/3/23 + * + * 小巴订单管理 + */ +public class OchBusOrderModel { + private final String TAG = OchBusOrderModel.class.getSimpleName(); + private int currentLineId = -1; + private int currentStationIndex = 0; //因为服务端和前台对于当前站不一致,所以设置两个current index, 一个用于前台展示, 一个用于服务端接口请求 + private int backgroundCurrentStationIndex = 0;//A->B 此处值是A站点索引 + /** + * 运营状态、后端更具运营状态来判断车辆是否派单 + */ + private boolean mIsWorking = false; + private static volatile OchBusOrderModel sInstance; + public double mLongitude = 0; + public double mLatitude = 0; + private Context mContext; + private Disposable mBusOrdersDisposable; //定时轮询小巴车订单 + private List prevBusOrderIds = new ArrayList<>(); + private final List< OchBusStation > stationList = new ArrayList<>(); + private OchBusRoutesResult ochBusRoutesResult = null; + /** + * 用来表示是否正在开往下一站 + */ + private boolean isGoingToNextStation = false; + // 运营类型 + private static final int VEHICLE_TYPE = 10; + private static final int MSG_QUERY_BUS_STATION = 1001; + private static final long QUERY_BUS_STATION_DELAY = 5000; + + private CarOperationStatusCallback carOperationStatusCallback; + private RefreshBusStationsCallback refreshBusStationsCallback; + private SlidePannelHideCallback slidePannelHideCallback; + private IOCHBusControllerStatusCallback mControllerStatusCallback; //Model->Presenter:VR mode等 + + private boolean hadQueryLeaveAwayPassager = false; + + private final Handler handler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + if ( msg.what == MSG_QUERY_BUS_STATION ) { + OchBusOrderModel.getInstance().queryBusRoutes(); + return true; + } + return false; + } + }); + public static OchBusOrderModel getInstance() { + if ( sInstance == null ) { + synchronized ( OchBusOrderModel.class ) { + if ( sInstance == null ) { + sInstance = new OchBusOrderModel(); + } + } + } + return sInstance; + } + + private OchBusOrderModel() { + + } + public void init() { + mContext = AbsMogoApplication.getApp(); + // 2021/10/20 衡阳小巴业务,使用LenovoPad时需要此app自己获取坐标并上传 + String productFlavor = DebugConfig.getProductFlavor(); + if (productFlavor != null && productFlavor.contains("fPadLenovoOchBus")) { + MogoApisHandler.getInstance() + .getApis() + .getRegisterCenterApi() + .registerCarLocationChangedListener(TAG, mCarLocationChangedListener2); + MogoApisHandler.getInstance() + .getApis() + .getStatusManagerApi() + .registerStatusChangedListener( TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener ); + } + + //2022.1.28 + // 调用Disposable.dispose() 时候会出现InterruptedException 导致出现崩溃 + // The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the excTeption has nowhere to go to begin with + RxJavaPlugins.setErrorHandler(new Consumer() { + @Override + public void accept(Throwable e) { + if (e instanceof UndeliverableException) { + e = e.getCause(); + Log.d(TAG,"UndeliverableException"); + } + if ((e instanceof IOException)) {// + // fine, irrelevant network problem or API that throws on cancellation + Log.d(TAG,"IOException"); + return; + } + if (e instanceof InterruptedException) { + // fine, some blocking code was interrupted by a dispose call + Log.d(TAG,"InterruptedException"); + return; + } + if ((e instanceof NullPointerException) || (e instanceof IllegalArgumentException)) { + // that's likely a bug in the application + Log.d(TAG,"NullPointerException or IllegalArgumentException"); + Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); + return; + } + if (e instanceof IllegalStateException) { + // that's a bug in RxJava or in a custom operator + Log.d(TAG,"IllegalStateException"); + Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); + return; + } + Log.d(TAG,"Undeliverable exception"); + } + }); + + //2021/10/20 轮询小巴车订单,暂时用来播报 + startLoopBusOrders(); + } + + public void setCarOperationStatusCallback(CarOperationStatusCallback callback){ + this.carOperationStatusCallback = callback; + } + public void setRefreshBusStationsCallback(RefreshBusStationsCallback callback){ + this.refreshBusStationsCallback = callback; + } + public void setSlidePannelHideCallback(SlidePannelHideCallback callback){ + this.slidePannelHideCallback = callback; + } + public void setControllerStatusCallback(IOCHBusControllerStatusCallback callback) { + this.mControllerStatusCallback = callback; + } + /** + * 轮询bus待服务订单 + */ + private void startLoopBusOrders() { + if (mBusOrdersDisposable != null && !mBusOrdersDisposable.isDisposed()) { + return; + } + mBusOrdersDisposable = Observable.interval(OchBusConst.LOOP_DELAY, + OchBusConst.LOOP_PERIOD_1S, TimeUnit.MILLISECONDS,Schedulers.trampoline()) + .map((aLong -> aLong + 1)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> queryBusOrders()); + } + + private void queryBusOrders() { + OCHBusServiceManager.getInstance().queryBusOrders(mContext, new OCHServiceCallback() { + @Override + public void onSuccess(OchBusOrdersResponse o) { + if (o.data != null && o.data.orders != null && o.data.orders.size() > 0) { + Logger.d( TAG, "获取到bus订单数据: " + o.data.orders.toString() ); + List busOrders = o.data.orders; + for (int i = 0; i < busOrders.size(); i++) { + OchBusOrder order = busOrders.get(i); + if (order == null) return; + if (TextUtils.isEmpty(order.getPassengerPhone())) return; + if (prevBusOrderIds.contains(order.getOrderId())) continue; + try { + String tailNum = null; + try { + tailNum = order.getPassengerPhone().substring(order.getPassengerPhone().length() - 4); + } catch (Exception e) { + e.printStackTrace(); + tailNum = order.getPassengerPhone(); + } + Logger.d(TAG, "TTS:" + tailNum); + AIAssist.getInstance(mContext).speakTTSVoice("接到新订单,尾号 " + tailNum + " 上车站点为 " + order.getStartStationName()); + prevBusOrderIds.add(order.getOrderId()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + @Override + public void onFail(String failMsg) { + + } + }); + } + + public void release(){ + if (mBusOrdersDisposable != null) { + mBusOrdersDisposable.dispose(); + } + startOrStopOrderLoop(false); + MogoApisHandler.getInstance() + .getApis() + .getStatusManagerApi() + .unregisterStatusChangedListener(TAG, StatusDescriptor.VR_MODE, mMogoStatusChangedListener); + + // 注销到达起始站围栏监听 + MogoApisHandler.getInstance() + .getApis() + .getRegisterCenterApi() + .unregisterCarLocationChangedListener(TAG, mCarLocationChangedListener2); + } + private Object readResolve() { + // 阻止反序列化,必须实现 Serializable 接口 + return sInstance; + } + private IMogoStatusChangedListener mMogoStatusChangedListener = new IMogoStatusChangedListener() { + // VR mode变更回调 + @Override + public void onStatusChanged(StatusDescriptor descriptor, boolean isTrue) { + if (StatusDescriptor.VR_MODE == descriptor) { + if (mControllerStatusCallback != null) { + mControllerStatusCallback.onVRModeChanged(isTrue); + } + } + } + }; + // 自车定位 + private IMogoCarLocationChangedListener2 mCarLocationChangedListener2 = new IMogoCarLocationChangedListener2() { + @Override + public void onCarLocationChanged(MogoLatLng latLng) { + + } + + @Override + public void onCarLocationChanged2( Location location ) { +// Log.d(TAG,"location = "+location.getLongitude()+","+location.getLatitude()); + IMogoServiceApis apis = MogoApisHandler.getInstance().getApis(); + MogoLocation mogoLocation = new MogoLocation(); + mogoLocation.setAccuracy(location.getAccuracy()); + mogoLocation.setProvider(location.getProvider()); + mogoLocation.setLongitude(location.getLongitude()); + mogoLocation.setLatitude(location.getLatitude()); + mogoLocation.setSpeed(location.getSpeed()); + mogoLocation.setBearing(location.getBearing()); + // TODO: 2021/9/2 因0830新版server后台只能过滤locType=1&&satellites>=4的定位数据,暂固化值,后续优化 + mogoLocation.setLocType(1); + mogoLocation.setSatellite(4); + /** + * TODO: 2021/10/20 + * 因ALocationClient实际无坐标返回,所以此处从custom map中AMapViewWrapper获取坐标并反馈回用于坐标上传 + * {@link com.mogo.map.impl.custom.location.ALocationClient} + */ + apis.getLocationInfoApi().provideLocation(mogoLocation); + + mLongitude = location.getLongitude(); + mLatitude = location.getLatitude(); + + if (mControllerStatusCallback != null) { + mControllerStatusCallback.onCarLocationChanged(location); + } + } + }; + /** + * 查询小巴路线 + */ + public void queryBusRoutes() { + Logger.d( TAG, "查询小巴路线"); + OCHBusServiceManager.getInstance().queryBusRoutes(mContext, new OCHServiceCallback() { + @Override + public void onSuccess(OchBusRoutesResponse data) { + if ( data == null + || data.getResult() == null + || data.getResult().getSites() == null + || data.getResult().getSites().isEmpty() ) { + return; + } + Logger.d( TAG, "获取到小巴路线数据: " + data ); + renderBusStationsStatus( data.getResult()); + } + @Override + public void onFail(String failMsg) { + // 重复请求小巴路线,直至成功 + queryBusStationDelay(); + } + }); + + } + + /** + * 测试、重置站点状态 + */ + public void debugResetStationStatus() { + Logger.d( TAG, "测试、重置站点状态"); + OCHBusServiceManager.getInstance().debugResetStationStatus(mContext, currentLineId, new OCHServiceCallback() { + @Override + public void onSuccess(OchBusRoutesResponse o) { + Logger.d(TAG, "获取到小巴路线数据: " + o); + isGoingToNextStation = false; + if (o.getResult() == null || o.getResult().getSites() == null || o.getResult().getSites().isEmpty()) { + return; + } + renderBusStationsStatus(o.getResult()); + } + + @Override + public void onFail(String failMsg) { + // 重复请求小巴路线,直至成功 + queryBusStationDelay(); + } + }); + + } + /** + * 离站上报 + */ + public void leaveStation(boolean isOneWayOver,boolean isRestart){ + Log.d(TAG,"leaveStation-backgroundCurrentStationIndex = "+backgroundCurrentStationIndex); + OCHBusServiceManager.getInstance().leaveStation(mContext, stationList.get(backgroundCurrentStationIndex).getSeq(), stationList.get(backgroundCurrentStationIndex).getSiteId(), new OCHServiceCallback() { + @Override + public void onSuccess(OchBusRoutesResponse o) { + if ( o.getResult() == null || o.getResult().getSites() == null || o.getResult().getSites().isEmpty() ) { + return; + } + if (!isOneWayOver){ + Logger.d( TAG, "自动驾驶开启开往下一站====" ); + //需要更改当前站和下一站的状态 然后渲染 + RenderLeaveStationSuccess(o.getResult(),isRestart); + }else { + Logger.d( TAG, "单程真的结束了====" ); + isGoingToNextStation = false; + currentStationIndex = 0; + backgroundCurrentStationIndex = 0; + CallerAutoPilotManager.INSTANCE.cancelAutoPilot(); + queryBusRoutes(); + } + } + @Override + public void onFail(String failMsg) { + if (!NetworkUtils.isConnected(mContext)) { + TipToast.shortTip("网络异常,请稍后重试"); + } + } + }); + } + /** + * 离站上报成功后渲染站点 + * 服务端返回的OchBusRoutesResult逻辑, 离开站为当前站, 到达下一站后才会将下一站置为当前站, + * 车机端展示是离开当前站,下一站设置为当前站, 所以服务端数据回来要做处理,不能直接渲染 + */ + private void RenderLeaveStationSuccess(OchBusRoutesResult result,boolean isRestart) { + renderBusStationsStatus(result); + if (slidePannelHideCallback != null) { + slidePannelHideCallback.hideSlidePanel(); + } + //开启自动驾驶 + startAutopilot(isRestart); + if (isGoingToNextStation) { + // 为了避免恢复自动驾驶时重复的接口请求 + return; + } + isGoingToNextStation = true; + AIAssist.getInstance( mContext ).speakTTSVoice( "欢迎乘坐’蘑菇车联‘无人驾驶小巴车,请您坐好,注意乘车安全,行程即将开始" ); + } + + private void startAutopilot(boolean isRestart) { + OchBusStation currentStation = stationList.get( currentStationIndex -1); + OchBusStation nextStation = stationList.get( currentStationIndex); + +// if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE +// == Integer.parseInt(DebugConfig.getAutoPilotStatus())) { +// TipToast.shortTip("自动驾驶状态为不可用!"); +// } + AutopilotControlParameters currentAutopilot = new AutopilotControlParameters(); + currentAutopilot.isSpeakVoice = !isRestart; + currentAutopilot.startName = PinYinUtil.getPinYinHeadChar(currentStation.getName()); + currentAutopilot.endName = PinYinUtil.getPinYinHeadChar(nextStation.getName()); + currentAutopilot.startLatLon = new AutopilotControlParameters.AutoPilotLonLat( currentStation.getLat(), currentStation.getLon() ); + currentAutopilot.endLatLon = new AutopilotControlParameters.AutoPilotLonLat( nextStation.getLat(), nextStation.getLon() ); + currentAutopilot.vehicleType = VEHICLE_TYPE; + Logger.d( TAG, "开启自动驾驶====" + currentAutopilot.toString() + +" startLatLon="+currentStation.getName()+",endLatLon="+nextStation.getName()); + CallerAutoPilotManager.INSTANCE.startAutoPilot(currentAutopilot); + if (mControllerStatusCallback != null) { + mControllerStatusCallback.startOpenAutopilot(); + } + } + + /** + * 到站后重置站点状态 + */ + private void arriveSiteStation(boolean isRestart) { + Log.d(TAG,"arriveSiteStation-currentStationIndex = "+currentStationIndex); + OCHBusServiceManager.getInstance().arriveSiteStation(mContext, stationList.get(currentStationIndex).getSeq(), stationList.get(currentStationIndex).getSiteId() + , new OCHServiceCallback() { + @Override + public void onSuccess(BaseData o) { + Log.d(TAG,"arriveSiteStation success"); + if (!isRestart){ + renderArriveBusStation(); + } + } + + @Override + public void onFail(String failMsg) { + if (!NetworkUtils.isConnected(mContext)) { + TipToast.shortTip("网络异常,请稍后重试"); + } + } + }); + } + + private void renderArriveBusStation() { + List< OchBusStation > site = ochBusRoutesResult.getSites(); + if (site != null && site.size() > 0){ + backgroundCurrentStationIndex = currentStationIndex; + if (refreshBusStationsCallback != null){ + refreshBusStationsCallback.refreshBusStations(stationList, currentStationIndex, getNextStopStation(),true); + } + } + } + + /** + * 查询到站下车乘客 + */ + private void queryStationLeaveAwayPassengers() { + Logger.d( TAG, "查询到站下车乘客"); + + OCHBusServiceManager.getInstance().queryStationLeaveAwayPassengers(mContext, stationList.get(currentStationIndex).getSeq(), stationList.get(currentStationIndex).getSiteId() + , new OCHServiceCallback() { + @Override + public void onSuccess(QueryLeaveAwayPassengersResponse o) { + hadQueryLeaveAwayPassager = true; + arriveSiteStation(false); + playLeavePassengersMsg( o ); + queryBusOrders(); + } + + @Override + public void onFail(String failMsg) { + hadQueryLeaveAwayPassager = true; + arriveSiteStation(false); + } + }); + } + /** + * 收车 + */ + public void stopTakeOrder(){ + OCHBusServiceManager.getInstance().stopTakeOrder(mContext, new OCHServiceCallback() { + @Override + public void onSuccess(BaseData o) { + mIsWorking = !mIsWorking; + carOperationStatusCallback.changeOperationStatus(isWorking()); + startOrStopOrderLoop(mIsWorking); + } + @Override + public void onFail(String failMsg) { + if (!NetworkUtils.isConnected(mContext)) { + TipToast.shortTip("网络异常,请稍后重试"); + }else { + TipToast.shortTip(failMsg); + } + } + }); + } + /** + * 出车 + */ + public void startTakeOrder(){ + OCHBusServiceManager.getInstance().startTakeOrder(mContext, new OCHServiceCallback() { + @Override + public void onSuccess(BaseData o) { + mIsWorking = !mIsWorking; + startOrStopOrderLoop(mIsWorking); + if ( stationList != null && stationList.size() > 0 ) { + AIAssist.getInstance( mContext ).speakTTSVoice( "车辆已整备完毕,请前往" + stationList.get( currentStationIndex ).getName() + "站点" ); + } + carOperationStatusCallback.changeOperationStatus(isWorking()); + queryBusRoutes(); + } + @Override + public void onFail(String failMsg) { + if (!NetworkUtils.isConnected(mContext)) { + TipToast.shortTip("网络异常,请稍后重试"); + }else { + TipToast.shortTip(failMsg); + } + } + }); + } + /** + * 查询运营状态 + */ + public void queryOperationStatus() { + Logger.d( TAG, "查询运营状态"); + OCHBusServiceManager.getInstance().queryOperationStatus(mContext, new OCHServiceCallback() { + @Override + public void onSuccess(OchBusOperationStatusResponse o) { + if ( o.data != null ) { + mIsWorking = o.data.serviceStatus == 1; + Logger.d( TAG, "查询运营状态 result.status: " + o.data.serviceStatus); + startOrStopOrderLoop(mIsWorking); + } + carOperationStatusCallback.changeOperationStatus(isWorking()); + } + @Override + public void onFail(String failMsg) { + if (!NetworkUtils.isConnected(mContext)) { + TipToast.shortTip("网络异常,请稍后重试"); + } + } + }); + } + /** + * 开启自动驾驶到下一站 + */ + public void autoDriveToNextStation( boolean isRestart ) { + if ( backgroundCurrentStationIndex >= stationList.size() - 1 ) { + // 当前站是最后一站,结束当前行程 + travelOver(); + return; + } + leaveStation(false,isRestart); + } + /** + * 渲染站点信息 + * 服务端返回的OchBusRoutesResult逻辑, 离开站为当前站, 到达下一站后才会将下一站置为当前站, + * 车机端展示是离开当前站,下一站设置为当前站, 所以服务端数据回来要做处理current index,不能直接渲染 + * @param result + */ + private void renderBusStationsStatus(OchBusRoutesResult result) { + if (result == null) return; + ochBusRoutesResult = result; + List< OchBusStation > site = result.getSites(); + currentLineId = result.getLineId(); + stationList.clear(); + stationList.addAll( site ); + for ( int i = 0; i < stationList.size(); i++ ) { + OchBusStation s = stationList.get( i ); + // 是否正在开往下一站 + if ( s.isLeaving()) { + isGoingToNextStation = true; + } + // 当前站点信息 + if (s.getDrivingStatus() == STATION_STATUS_STOPPED ) { + currentStationIndex = i; + break; + } + } + backgroundCurrentStationIndex = currentStationIndex; + OchBusStation currentStation = stationList.get(currentStationIndex); + Logger.d( TAG, "渲染站点信息服务端currentStationIndex="+currentStationIndex+" isLeaving()="+currentStation.isLeaving()); + if (currentStationIndex == 0 && !currentStation.isLeaving()){//当前站点是始发站,告诉服务端到达始发站。 如果没有这个节点, 服务器不知道始发站到达状态,订单开始站下在始发站的状态流转有问题 + arriveSiteStation(true); + } + // 美化是否开始 + if (FunctionBuildConfig.isDemoMode && ((currentStationIndex > 0 && currentStationIndex < stationList.size()-1) + || (stationList.get(0).isLeaving() || stationList.get(stationList.size() -1).isLeaving()))){//行驶过程中设置美化 + FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true; + } + if (refreshBusStationsCallback != null){ + if (currentStation.isLeaving()){//如果服务端的当前站是leaving状态,展示当前站需要+1 + currentStationIndex ++; + refreshBusStationsCallback.refreshBusStations(stationList, currentStationIndex, getNextStopStation(),false); + }else{ + refreshBusStationsCallback.refreshBusStations(stationList, currentStationIndex, getNextStopStation(),true); + } + } + if ( currentStation.isLeaving() && slidePannelHideCallback != null) { + slidePannelHideCallback.hideSlidePanel(); + } + } + + /** + * 重置下一站 + * + * @param lastStopStation + */ + private void resetNextStopStation( int lastStopStation ) { + Logger.d( TAG, "重置下一站"); + int nextStopStation = getNextStopStation(); + if ( nextStopStation < 0 ) { + return; + } + if ( lastStopStation <= nextStopStation || nextStopStation <= currentStationIndex ) { + return; + } + if ( CallerAutoPilotStatusListenerManager.INSTANCE.getAutoPilotStatusInfo().getState() + == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING ) { + // 自动驾驶中动态设置下一个停靠站点/ + autoDriveToNextStation( true ); + } + } + /** + * 根据订单状态、获取下一站靠站的的站点 + * + * @return -1 当前已是最后一个站点 + */ + private int getNextStopStation() { + if ( currentStationIndex >= stationList.size() - 1 ) { + return -1; + } + int nextStationIndex = currentStationIndex + 1; + for ( ; nextStationIndex < stationList.size() - 1; nextStationIndex++ ) { + if ( stationList.get( nextStationIndex ).getIfStop() == 1 ) { + break; + } + break; + } + return nextStationIndex; + } + /** + * 延时查询站点信心 + */ + private void queryBusStationDelay() { + handler.sendEmptyMessageDelayed( MSG_QUERY_BUS_STATION, QUERY_BUS_STATION_DELAY ); + } + + /** + * 在踩刹车、控制方向盘等操作后,会停止自动驾驶,重启自动驾驶的话相当于重新设置自动驾驶目的地 + */ + public void restartAutopilot() { + Logger.d( TAG, "重启自动驾驶===" + isGoingToNextStation ); + if ( isGoingToNextStation ) { + autoDriveToNextStation( true ); + } + } + /** + * 播报下车乘客信息 + * + * @param awayPassengersResponse + */ + private void playLeavePassengersMsg( QueryLeaveAwayPassengersResponse awayPassengersResponse ) { + Logger.d( TAG, "播报下车乘客信息currentStationIndex="+currentStationIndex); + + if ( currentStationIndex > stationList.size() - 1 ) { + return; + } + String station = stationList.get( currentStationIndex ).getName(); + StringBuilder builder = new StringBuilder( "已到达" ); + builder.append( station ); + if ( !station.endsWith( "站" ) ) { + builder.append( "站" ); + } + if ( awayPassengersResponse == null || awayPassengersResponse.data == null || awayPassengersResponse.data.orders == null || awayPassengersResponse.data.orders.isEmpty() ) { + Logger.d( TAG, "播报下车乘客信息为null"); + } else { + builder.append( ",请尾号为 " ); + for ( QueryLeaveAwayPassengersResponse.LeaveAwayPassenger leaveAwayPassenger : awayPassengersResponse.data.orders ) { + if ( leaveAwayPassenger == null ) { + continue; + } + String tailNum = null; + try { + tailNum = leaveAwayPassenger.passengerPhone.substring(leaveAwayPassenger.passengerPhone.length() - 4); + } catch (Exception e) { + e.printStackTrace(); + tailNum = leaveAwayPassenger.passengerPhone; + } + builder.append( tailNum ).append( "。" ); + } + builder.append( "的乘客下车" ); + } + builder.append(",带好随身物品,下车请注意安全"); + Logger.d(TAG, "TTS:" + builder.toString()); + AIAssist.getInstance( mContext ).speakTTSVoice( builder.toString() ); + } + /** + * 修改小巴运营状态 + */ + public void onChangeOperationStatus() { + Logger.d( TAG, "修改小巴运营状态"); + if (isWorking()){//收车 + stopTakeOrder(); + }else {//出车 + startTakeOrder(); + } + } + /** + * 行程结束 + */ + private void travelOver() { +// Logger.d( TAG, "行程结束"); + + if ( currentStationIndex >= stationList.size() ) { + Logger.e( TAG, "travel over index out of station list" ); + return; + } + Logger.d( TAG, "单程结束====" ); + CallerAutoPilotManager.INSTANCE.cancelAutoPilot(); + AIAssist.getInstance( mContext ).speakTTSVoice( "感谢您体验'蘑菇车联'无人驾驶小巴车,请您携带好随身物品,我们下次再见" ); + leaveStation(true,true); + } + public boolean isWorking() { + return mIsWorking; + } + /** + * 到站 + * @param data + */ + public void onArriveAt( AutopilotStationInfo data){ + if ( currentStationIndex > stationList.size() - 1 ) { + Logger.e( TAG, "到站异常,取消后续操作结束" ); + return; + } + if (FunctionBuildConfig.isDemoMode && currentStationIndex == stationList.size() - 1){//到达最后一站结束美化 + FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = false; + } + Logger.d( TAG, "到站====currentStationIndex=" + currentStationIndex); + isGoingToNextStation = false; + // 到达站点后,更新站点状态 +// currentStationIndex = getNextStopStation(); + queryStationLeaveAwayPassengers(); + UiThreadHandler.postDelayed(new Runnable() {// 先查询下车乘客,再上报到站,便于后台筛查下车订单 + @Override + public void run() { + if (!hadQueryLeaveAwayPassager){ + arriveSiteStation(false); + } + hadQueryLeaveAwayPassager = false; + } + },1500); + } + public boolean isGoingToNextStation() { + return isGoingToNextStation; + } + + // 车机端上传心跳数据(只在出车状态时上传) + public void runCarHeartbeat() { + OCHBusServiceManager.getInstance().runCarHeartbeat(mContext, mLongitude, mLatitude, + new OCHServiceCallback() { + @Override + public void onSuccess(BaseData data) { + + } + + @Override + public void onFail(String failMsg) { + + } + }); + } + + private void startOrStopOrderLoop(boolean start) { + Logger.d(TAG, "startOrStopOrderLoop() " + start); + if (start) { + OchBusModelLoopManager.getInstance().startHeartbeatLoop(); + } else { + OchBusModelLoopManager.getInstance().stopHeartbeatLoop(); + } + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusPresenter.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusPresenter.java new file mode 100644 index 0000000000..f5a0301b04 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/presenter/OchBusPresenter.java @@ -0,0 +1,265 @@ +package com.mogo.och.bus.presenter; +import android.location.Location; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; +import com.mogo.commons.mvp.Presenter; +import com.mogo.commons.voice.AIAssist; +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.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; +import com.mogo.och.bus.bean.OchBusStation; +import com.mogo.och.bus.callback.CarOperationStatusCallback; +import com.mogo.och.bus.callback.IOCHBusControllerStatusCallback; +import com.mogo.och.bus.callback.RefreshBusStationsCallback; +import com.mogo.och.bus.callback.SlidePannelHideCallback; +import com.mogo.och.bus.fragment.OchBusFragment; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * 网约车小巴 + * + * @author tongchenfei + */ +public class OchBusPresenter extends Presenter< OchBusFragment > implements CarOperationStatusCallback, RefreshBusStationsCallback, SlidePannelHideCallback, IMoGoAutopilotStatusListener, IOCHBusControllerStatusCallback { + private static final String TAG = "OchBusPresenter"; + private int currentAutopilotStatus = -1; + private boolean isAnimateRunning = false; + private List mStationList = new ArrayList<>(); + private int mCurrentStation = 0; + + public OchBusPresenter( OchBusFragment view ) { + super( view ); + //2021.11.1 鹰眼架构整合,由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口 + CallerAutoPilotStatusListenerManager.INSTANCE.addListener(TAG, this); + OchBusOrderModel.getInstance().init(); + } + + @Override + public void onCreate( @NonNull LifecycleOwner owner ) { + super.onCreate( owner ); + OchBusOrderModel.getInstance().queryOperationStatus(); + OchBusOrderModel.getInstance().queryBusRoutes(); + initModelListener(); + } + @Override + public void onDestroy(@NonNull LifecycleOwner owner) { + super.onDestroy(owner); + OchBusOrderModel.getInstance().release(); + releaseListener(); + } + public void initModelListener(){ + OchBusOrderModel.getInstance().setCarOperationStatusCallback(this); + OchBusOrderModel.getInstance().setRefreshBusStationsCallback(this); + OchBusOrderModel.getInstance().setSlidePannelHideCallback(this); + OchBusOrderModel.getInstance().setControllerStatusCallback(this); + } + public void releaseListener(){ + OchBusOrderModel.getInstance().setCarOperationStatusCallback(null); + OchBusOrderModel.getInstance().setRefreshBusStationsCallback(null); + OchBusOrderModel.getInstance().setSlidePannelHideCallback(null); + OchBusOrderModel.getInstance().setControllerStatusCallback(null); + } + public void queryBusRoutes(){ + OchBusOrderModel.getInstance().queryBusRoutes(); + } + public void debugResetStationStatus(){ + OchBusOrderModel.getInstance().debugResetStationStatus(); + } + public void autoDriveToNextStation(boolean isRestart){ + currentAutopilotStatus = -1; + OchBusOrderModel.getInstance().autoDriveToNextStation(isRestart); + } + public void restartAutopilot(){ + currentAutopilotStatus = -1; + OchBusOrderModel.getInstance().restartAutopilot(); + } + public void onChangeOperationStatus(){ + OchBusOrderModel.getInstance().onChangeOperationStatus(); + } + + @Override + public void changeOperationStatus(boolean changeStatus) { + if (mView != null) { + mView.changeOperationStatus(changeStatus); + } + } + + @Override + public void refreshBusStations(List stationList, int currentStation, int nextStation, boolean isArrived) { + mStationList.clear(); + mStationList.addAll(stationList); + mCurrentStation = currentStation; + functionDemoModeChange(); + Log.d("OchBusOrderModel ="," mCurrentStation ="+mCurrentStation); + if ( mView != null ) { + mView.refreshBusStations( stationList, currentStation, nextStation ,isArrived); + } + } + + private void functionDemoModeChange() { +// Log.d("OchBusOrderModel ="," functionDemoModeChange ="+mCurrentStation); + if (FunctionBuildConfig.isDemoMode + && ( + (mCurrentStation > 0 && mCurrentStation < mStationList.size()-1) + || ( + (mCurrentStation == 0 || mCurrentStation == mStationList.size() -1) + && OchBusOrderModel.getInstance().isGoingToNextStation() + ) + ) + ){ + mView.onAutopilotStatusChanged( IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING ,false); + } + } + + @Override + public void hideSlidePanel() { + if (mView != null){ + mView.hideSlidePanel(); + } + } + + @Override + public void onAutopilotArriveAtStation(@Nullable AutopilotStationInfo autopilotStationInfo) { + OchBusOrderModel.getInstance().onArriveAt(autopilotStationInfo); + } + + @Override + public void onAutopilotGuardian(@Nullable AutopilotGuardianStatusInfo autopilotGuardianStatusInfo) { + + } + + @Override + public void onAutopilotSNRequest() { + + } + + @Override + public void onAutopilotStatusResponse(@NotNull AutopilotStatusInfo autopilotStatusInfo) { + if (autopilotStatusInfo == null) return; + int state = autopilotStatusInfo.getState(); + Logger.d( TAG, "onStateChange: " + state +"currentAutopilotStatus = "+currentAutopilotStatus); + switch ( state ) { + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE: + if (currentAutopilotStatus != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE){ + if (currentAutopilotStatus == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){//2-->1语音提示 +// AIAssist.getInstance( getContext() ).speakTTSVoice( "已进入人工驾驶模式" ); + } + currentAutopilotStatus = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE; + // 设置UI【自动驾驶】按钮是否展示 + mView.onAutopilotEnableChange( true ); + if ( OchBusOrderModel.getInstance().isGoingToNextStation() ) { + mView.hideSlidePanel(); + } + if (FunctionBuildConfig.isDemoMode + && ( + (mCurrentStation > 0 && mCurrentStation < mStationList.size()-1) + || ( + (mCurrentStation == 0 || mCurrentStation == mStationList.size() -1) + && OchBusOrderModel.getInstance().isGoingToNextStation() + ) + ) + ){ + Log.d("OchBusOrderModel=","有美化功能"); + return; + } + // 改变UI自动驾驶状态 + mView.onAutopilotStatusChanged( currentAutopilotStatus ,isAnimateRunning); + } + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING: + runOnUIThread(()->mView.stopAutopilotAnimation()); + if (currentAutopilotStatus != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){ + currentAutopilotStatus = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING; + // 改变UI自动驾驶状态 + mView.onAutopilotStatusChanged( currentAutopilotStatus ,isAnimateRunning); + } + isAnimateRunning = false; + break; + case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE: + if (currentAutopilotStatus != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE){ + if (currentAutopilotStatus == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){//2-->0语音提示 +// AIAssist.getInstance( getContext() ).speakTTSVoice( "自动驾驶已停止,请人工接管" ); + } + currentAutopilotStatus = IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE; + if (FunctionBuildConfig.isDemoMode + && ( + (mCurrentStation > 0 && mCurrentStation < mStationList.size()-1) + || ( + (mCurrentStation == 0 || mCurrentStation == mStationList.size() -1) + && OchBusOrderModel.getInstance().isGoingToNextStation() + ) + ) + ){ + Log.d("OchBusOrderModel=","有美化功能"); + return; + } + mView.onAutopilotEnableChange( false ); + mView.onAutopilotStatusChanged( currentAutopilotStatus ,isAnimateRunning); + } + isAnimateRunning = false; + break; + default: + mView.onAutopilotEnableChange( false ); + break; + } + } + + @Override + public void onVRModeChanged(boolean isVRMode) { + runOnUIThread(() -> mView.onVRModeChanged(isVRMode)); + } + + @Override + public void onCarLocationChanged(Location location) { + if (null != location){ + runOnUIThread(() -> mView.updateSpeedView(location.getSpeed())); + } + } + + @Override + public void startOpenAutopilot() { + isAnimateRunning = true; + runOnUIThread(()->mView.startAutopilotAnimation()); + // TODO: 2021/8/20 无工控机环境, 手动调起自动驾驶开启返回结果,有工控机环境要删除 +// UiThreadHandler.postDelayed(new Runnable() { +// @Override +// public void run() { +// debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING); +// } +// },2300); + } + + private void runOnUIThread( Runnable executor ) { + if ( executor == null ) { + return; + } + if ( Looper.myLooper() != Looper.getMainLooper() ) { + UiThreadHandler.post( executor ); + } else { + executor.run(); + } + } + + /** + * 测试使用 + * @param status + */ + public void debugAutoPilotStatus(int status){ + AutopilotStatusInfo info = new AutopilotStatusInfo(); + info.setState(status); + onAutopilotStatusResponse(info); + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/receiver/TestOchBusBroadcastReceiver.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/receiver/TestOchBusBroadcastReceiver.java new file mode 100644 index 0000000000..132b5a87a6 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/receiver/TestOchBusBroadcastReceiver.java @@ -0,0 +1,40 @@ +package com.mogo.och.bus.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.och.bus.constant.OchBusConst; + +/** + * 测试小巴车的场景 + * + * @author donghongyu + * @date 4/26/21 12:08 PM + */ +public class TestOchBusBroadcastReceiver extends BroadcastReceiver { + private static final String TAG = "TestOchBusBroadcastReceiver"; + + private Context mContext; + + @Override + public void onReceive(Context context, Intent intent) { + try { + this.mContext = context; + int sceneType = intent.getIntExtra(OchBusConst.BROADCAST_TEST_BUS_CONTROL_TYPE_EXTRA_KEY, 0); + Logger.d(TAG, "sceneType:" + sceneType); + + // 分发场景 + dispatchSceneTest(sceneType); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void dispatchSceneTest(int sceneType) { + + } + + +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/util/PinYinUtil.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/util/PinYinUtil.java new file mode 100644 index 0000000000..aa826c9a68 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/util/PinYinUtil.java @@ -0,0 +1,31 @@ +package com.mogo.och.bus.util; + +import net.sourceforge.pinyin4j.PinyinHelper; + +/** + * @author: wangmingjun + * @date: 2021/11/26 + */ +public class PinYinUtil { + /** + * 得到中文字符串首字母 + * @param str 需要转化的中文字符串 + * @return 大写首字母缩写的字符串 + */ + public static String getPinYinHeadChar(String str) { + str = str.replaceAll("[\\p{P}‘’“”|+=¥$<>^~~]", ""); + StringBuilder convert = new StringBuilder(); + for (int j = 0; j < str.length(); j++) { + char word = str.charAt(j); + String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word); + if (pinyinArray != null) { + convert.append(pinyinArray[0].charAt(0)); + } else { + if (!"".equals(String.valueOf(word).trim())){ + convert.append(word); + } + } + } + return convert.toString().trim().toUpperCase(); + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/BusArcView.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/BusArcView.java new file mode 100644 index 0000000000..2fd6a41ce5 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/BusArcView.java @@ -0,0 +1,190 @@ +package com.mogo.och.bus.view; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.mogo.och.bus.R; + +/** + * created by wujifei on 2021/3/24 16:20 + * describe: + */ +public class BusArcView extends View { + + //中心的文字描述 + private String mDes = "km/h"; + //根据数据显示的圆弧Paint + private Paint mArcPaint; + //圆弧颜色 + private int mArcColor; + //圆弧的画笔的宽度 + private float mStrokeWith = getResources().getDimension(R.dimen.bus_ext_arcView_stroke_with); + //文字描述的paint + private Paint mTextPaint; + + //当前进度夹角大小 + private float mIncludedAngle = 0; + //当前数据 + private int currentValue; + //最大数据 + private int maxValue = 240; + //圆弧背景的开始和结束间的夹角大小 + private float mAngle = 270; + //上次绘制圆弧夹角 + private float lastAngle = 0; + + public BusArcView(Context context) { + this(context, null); + } + + public BusArcView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public BusArcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + //初始化paint + initPaint(); + //绘制弧度 + drawArc(canvas); + //绘制文本 + drawText(canvas); + } + + private void drawText(Canvas canvas) { + Rect mRect = new Rect(); + String mValue = String.valueOf(currentValue); + mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); + //绘制中心的数值 + mTextPaint.getTextBounds(mValue, 0, mValue.length(), mRect); + canvas.drawText(mValue, getWidth() / 2, getHeight() / 2 + mRect.height() / 2 - 10, mTextPaint); + + mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL)); + //绘制中心文字描述 + mTextPaint.setTextSize(getResources().getDimension(R.dimen.bus_ext_arcView_des_text_size)); + mTextPaint.getTextBounds(mDes, 0, mDes.length(), mRect); + canvas.drawText(mDes, getWidth() / 2, getHeight() * 17 / 20 + mRect.height() / 2, mTextPaint); + } + + private void drawArc(Canvas canvas) { + //绘制圆弧背景 + RectF mRectF = new RectF(mStrokeWith, mStrokeWith, getWidth() - mStrokeWith, getHeight() - mStrokeWith); + canvas.drawArc(mRectF, 135, mAngle, false, mArcPaint); + + //绘制当前数值对应的圆弧 + mArcPaint.setColor(mArcColor); + //根据当前数据绘制对应的圆弧 + canvas.drawArc(mRectF, 135, mIncludedAngle, false, mArcPaint); + } + + private void initPaint() { + //圆弧的paint + mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + //抗锯齿 + mArcPaint.setAntiAlias(true); + mArcPaint.setColor(Color.parseColor("#151D4C")); + //设置透明度(数值为0-255) + mArcPaint.setAlpha(100); + //设置画笔的画出的形状 + mArcPaint.setStrokeJoin(Paint.Join.ROUND); + mArcPaint.setStrokeCap(Paint.Cap.ROUND); + //设置画笔类型 + mArcPaint.setStyle(Paint.Style.STROKE); + //画笔宽度 + mArcPaint.setStrokeWidth(mStrokeWith); + + //中心文字的paint + mTextPaint = new Paint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setColor(Color.parseColor("#FFFFFF")); + //设置文本的对齐方式 + mTextPaint.setTextAlign(Paint.Align.CENTER); + //mTextPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.dp_12)); + mTextPaint.setTextSize(getResources().getDimension(R.dimen.bus_ext_arcView_center_text_size)); + + } + + + /** + * 为绘制弧度及数据设置动画 + * + * @param startAngle 开始的弧度 + * @param currentAngle 需要绘制的弧度 + * @param time 动画执行的时长 + */ + private void setAnimation(float startAngle, float currentAngle, int time) { + //绘制当前数据对应的圆弧的动画效果 + ValueAnimator progressAnimator = ValueAnimator.ofFloat(startAngle, currentAngle); + progressAnimator.setDuration(time); + progressAnimator.setTarget(mIncludedAngle); + progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mIncludedAngle = (float) animation.getAnimatedValue(); + //重新绘制,不然不会出现效果 + postInvalidate(); + } + }); + //开始执行动画 + progressAnimator.start(); + } + + + /** + * 设置弧形颜色 + * + * @param value 颜色值 + */ + public void setArcColor(int value) { + mArcColor = value; + } + + /** + * 设置数据 + * + * @param value 当前绘制的值 + */ + public void setValues(int value) { + //完全覆盖 + if (value > maxValue) { + value = maxValue; + } + if (value < 0) { + value = 0; + } + currentValue = value; + //计算弧度比重 + float scale = (float) currentValue / maxValue; + //计算弧度 + float currentAngle = scale * mAngle; + //开始执行动画 + setAnimation(lastAngle, currentAngle, 1000); + lastAngle = currentAngle; + //重新绘制 + postInvalidate(); + } + + + private float dp2px(float dp) { + DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); + return dp * metrics.density; + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/NoTouchConstraintLayout.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/NoTouchConstraintLayout.java new file mode 100644 index 0000000000..558a515bd9 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/NoTouchConstraintLayout.java @@ -0,0 +1,37 @@ +package com.mogo.och.bus.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.mogo.commons.debug.DebugConfig; + +/** + * 强制拦截所有touch时间的约束布局 + * + * @author tongchenfei + */ +public class NoTouchConstraintLayout extends ConstraintLayout { + public NoTouchConstraintLayout(Context context) { + super(context); + } + + public NoTouchConstraintLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NoTouchConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if(DebugConfig.isDebug()){ + return super.onInterceptTouchEvent(ev); + }else { + return true; + } + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/SlidePanelView.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/SlidePanelView.java new file mode 100644 index 0000000000..53d27b181b --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/SlidePanelView.java @@ -0,0 +1,264 @@ +package com.mogo.och.bus.view; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import androidx.annotation.Nullable; + +import com.mogo.och.bus.R; + +/** + * 滑块滑动面板 + * + * @author tongchenfei + */ +public class SlidePanelView extends View { + private static final String TAG = "SlidePanelView"; + + public SlidePanelView(Context context) { + this(context, null); + } + + public SlidePanelView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidePanelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.SlidePanelView); + textSize = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_textSize, textSize); + BLOCK_START_X = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_X, BLOCK_START_X); + BLOCK_START_Y = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_Y, BLOCK_START_Y); + NORMAL_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_LEFT, NORMAL_TEXT_MARGIN_LEFT); + NORMAL_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_RIGHT, NORMAL_TEXT_MARGIN_RIGHT); + SHORT_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_LEFT, SHORT_TEXT_MARGIN_LEFT); + SHORT_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_RIGHT, SHORT_TEXT_MARGIN_RIGHT); + init(); + } + + private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint blockPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private static int textSize = 40; + private static int BLOCK_START_X = 15; + private static int BLOCK_START_Y = 15; + private static int NORMAL_TEXT_MARGIN_LEFT = 40; + private static int NORMAL_TEXT_MARGIN_RIGHT = 60; + private static int SHORT_TEXT_MARGIN_LEFT = 60; + private static int SHORT_TEXT_MARGIN_RIGHT = 70; + + private int textMarginLeft = NORMAL_TEXT_MARGIN_LEFT; + private int textMarginRight = NORMAL_TEXT_MARGIN_RIGHT; + + private OnSlidePanelMoveToEndListener moveToEndListener; + + private int blockWidth = 0; + private int blockOffset = 0; + + private float lastX; + private boolean isToEnd = false; + + private static final String STRING_SLIDE_TO_RIGHT = "向右滑动"; + private RectF bgRectF; + private Bitmap bmBlock; + + private final Matrix gradientMatrix = new Matrix(); + private float matrixTranslate; + private final Rect textRect = new Rect(); + private LinearGradient textGradient; + + private ObjectAnimator matrixAnim; + + private String blockText = STRING_SLIDE_TO_RIGHT; + private Paint.FontMetrics blockTextMetrics = new Paint.FontMetrics(); + + private static final int GRADIENT_OFFSET = 200; + + public void setOnSlidePanelMoveToEndListener(OnSlidePanelMoveToEndListener moveToEndListener) { + this.moveToEndListener = moveToEndListener; + } + + private void setBlockOffset(int blockOffset) { + this.blockOffset = blockOffset; + invalidate(); + } + + private void setMatrixTranslate(float matrixTranslate) { + this.matrixTranslate = matrixTranslate; + invalidate(); + } + + public void setText(String text) { + this.blockText = text; + requestLayout(); + invalidate(); + } + + private void init() { + bgPaint.setColor(Color.parseColor("#CC0F1325")); + bgPaint.setStyle(Paint.Style.FILL); + + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(textSize); + textPaint.setTextAlign(Paint.Align.LEFT); + textGradient = new LinearGradient(-GRADIENT_OFFSET, 0, 0, 0, new int[]{0x33ffffff, 0xffffffff, 0x33ffffff}, null, Shader.TileMode.CLAMP); + textGradient.setLocalMatrix(gradientMatrix); + textPaint.setShader(textGradient); + textPaint.getFontMetrics(blockTextMetrics); + + bmBlock = BitmapFactory.decodeResource(getResources(), R.drawable.bus_base_slide_block); + blockWidth = bmBlock.getWidth(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize; + int heightSize; + + if (blockText.length() < 5) { + textMarginLeft = SHORT_TEXT_MARGIN_LEFT; + textMarginRight = SHORT_TEXT_MARGIN_RIGHT; + } else { + textMarginLeft = NORMAL_TEXT_MARGIN_LEFT; + textMarginRight = NORMAL_TEXT_MARGIN_RIGHT; + } + + if (widthMode == MeasureSpec.AT_MOST) { + // 宽度根据图片大小,字符串长度,各种间隔确定 + // 高度根据图片大小和上下间隔确定 + textPaint.getTextBounds(blockText, 0, blockText.length(), textRect); + widthSize = BLOCK_START_X * 2 + bmBlock.getWidth() + textMarginLeft + textMarginRight + textRect.width(); + heightSize = BLOCK_START_Y * 2 + bmBlock.getHeight(); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + private float textOffset = 0; + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + bgRectF = new RectF(0, 0, w, h); + + if (matrixAnim != null) { + matrixAnim.cancel(); + } + textOffset = (getHeight() - blockTextMetrics.ascent - blockTextMetrics.descent) / 2; + matrixAnim = ObjectAnimator.ofFloat(this, "matrixTranslate", 0, w + GRADIENT_OFFSET).setDuration(2000); + matrixAnim.setRepeatCount(ValueAnimator.INFINITE); + matrixAnim.start(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (matrixAnim != null) { + matrixAnim.start(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (matrixAnim != null) { + matrixAnim.cancel(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (x > BLOCK_START_X + blockOffset && x < blockWidth + BLOCK_START_X + blockOffset && y > BLOCK_START_Y && y < getHeight() - BLOCK_START_Y) { + isToEnd = false; + lastX = x; + } + break; + case MotionEvent.ACTION_MOVE: + if (lastX != 0) { + blockOffset = (int) (x - lastX); + if (blockOffset < 0) { + blockOffset = 0; + } + if (blockOffset + BLOCK_START_X + blockWidth > getWidth()) { + // 超出右边界 + blockOffset = getWidth() - BLOCK_START_X - blockWidth; + if (!isToEnd) { + isToEnd = true; + if (moveToEndListener != null) { + moveToEndListener.moveToEnd(); + } + startBlockBackAnim(); + } + } + invalidate(); + } + break; + case MotionEvent.ACTION_UP: + // 执行滑块回归动画 + if (!isToEnd) { + startBlockBackAnim(); + } + break; + default: + break; + } + + return true; + } + + private void startBlockBackAnim() { + ObjectAnimator animator = ObjectAnimator.ofInt(this, "blockOffset", blockOffset, 0); + animator.setInterpolator(new DecelerateInterpolator()); + animator.setDuration(1000 * blockOffset / getWidth()); + animator.start(); + lastX = 0; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + // 画背景 + canvas.drawRoundRect(bgRectF, (float) getHeight() / 2, (float) getHeight() / 2, bgPaint); + // 画文字 + gradientMatrix.setTranslate(matrixTranslate, 0); + textGradient.setLocalMatrix(gradientMatrix); + canvas.save(); + canvas.drawText(blockText, blockWidth + BLOCK_START_X + textMarginLeft, textOffset, textPaint); + canvas.restore(); + // 画滑块 + canvas.drawBitmap(bmBlock, BLOCK_START_X + blockOffset, BLOCK_START_Y, blockPaint); + } + + public interface OnSlidePanelMoveToEndListener { + /** + * 滑块滑到了末尾 + */ + void moveToEnd(); + } +} diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/VerticalDashLineView.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/VerticalDashLineView.java new file mode 100644 index 0000000000..250d4a41b6 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/view/VerticalDashLineView.java @@ -0,0 +1,64 @@ +package com.mogo.och.bus.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.Nullable; + +/** + * 垂直虚线 + * + * @author tongchenfei + */ +public class VerticalDashLineView extends View { + public VerticalDashLineView(Context context) { + this(context,null); + } + + public VerticalDashLineView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs,0); + } + + public VerticalDashLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private final Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path dashPath = new Path(); + + private void init(){ + linePaint.setColor(Color.GREEN); + linePaint.setStyle(Paint.Style.STROKE); + linePaint.setStrokeWidth(2); + linePaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0)); + } + + public void setGradient(int startColor, int endColor) { + LinearGradient linearGradient = new LinearGradient(0, 0, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP); + linePaint.setShader(linearGradient); + invalidate(); + } + + public void setColor(int color) { + linePaint.setShader(null); + linePaint.setColor(color); + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + dashPath.reset(); + dashPath.moveTo((float) getWidth()/2, 0); + dashPath.lineTo((float) getWidth()/2,getHeight()); + canvas.drawPath(dashPath,linePaint); + } +} diff --git a/OCH/mogo-och-bus/src/main/res/color/bus_autopilot_text_color_selector.xml b/OCH/mogo-och-bus/src/main/res/color/bus_autopilot_text_color_selector.xml new file mode 100644 index 0000000000..15f6897792 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/color/bus_autopilot_text_color_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_base_icon_not_in_autopilot.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_base_icon_not_in_autopilot.png new file mode 100644 index 0000000000..927296d690 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_base_icon_not_in_autopilot.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_base_slide_block.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_base_slide_block.png new file mode 100644 index 0000000000..ed7b293b90 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_base_slide_block.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_disable_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_disable_autopilot_icon.png new file mode 100644 index 0000000000..170f254cd1 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_disable_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_icon_arrived_station.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_icon_arrived_station.png new file mode 100644 index 0000000000..8a065b66dd Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_icon_arrived_station.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_icon_arriving_station.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_icon_arriving_station.png new file mode 100644 index 0000000000..4ed57a0e30 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_icon_arriving_station.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_loading_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_loading_autopilot_icon.png new file mode 100644 index 0000000000..f21a1081f1 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_loading_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_och_dot_line.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_och_dot_line.png new file mode 100644 index 0000000000..a720a532ea Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_och_dot_line.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_right_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_right_autopilot_icon.png new file mode 100644 index 0000000000..cc2b18083d Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_right_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_setting_btn_bg.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_setting_btn_bg.png new file mode 100644 index 0000000000..ba41bf3a53 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_setting_btn_bg.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_switch_map_angle.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_switch_map_angle.png new file mode 100644 index 0000000000..3e1b96f3e3 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_switch_map_angle.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_wrong_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_wrong_autopilot_icon.png new file mode 100644 index 0000000000..0c8988acb3 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1440/bus_wrong_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/end_maker_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/end_maker_icon.png new file mode 100755 index 0000000000..8acf113151 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/end_maker_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/icon_station_start_end.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/icon_station_start_end.png new file mode 100644 index 0000000000..04580a8f0d Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/icon_station_start_end.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/start_maker_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/start_maker_icon.png new file mode 100644 index 0000000000..9eca61e199 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi-2560x1600/start_maker_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_icon_in_autopilot.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_icon_in_autopilot.png new file mode 100644 index 0000000000..75c26c3d71 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_icon_in_autopilot.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_icon_not_in_autopilot.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_icon_not_in_autopilot.png new file mode 100644 index 0000000000..21dc719ec9 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_icon_not_in_autopilot.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_notice_box_bg.9.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_notice_box_bg.9.png new file mode 100644 index 0000000000..8b4b579b56 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_notice_box_bg.9.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_slide_block.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_slide_block.png new file mode 100644 index 0000000000..8ffd0abe52 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_base_slide_block.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_disable_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_disable_autopilot_icon.png new file mode 100644 index 0000000000..170f254cd1 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_disable_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_dot_line.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_dot_line.png new file mode 100644 index 0000000000..186001352c Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_dot_line.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_ic_autopilot.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_ic_autopilot.png new file mode 100644 index 0000000000..be978145dc Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_ic_autopilot.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_arrived_station.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_arrived_station.png new file mode 100644 index 0000000000..a676a789c3 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_arrived_station.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_arriving_station.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_arriving_station.png new file mode 100644 index 0000000000..e1fd463963 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_arriving_station.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_not_arrive_station.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_not_arrive_station.png new file mode 100644 index 0000000000..e0bb24c526 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_icon_not_arrive_station.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_loading_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_loading_autopilot_icon.png new file mode 100644 index 0000000000..f21a1081f1 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_loading_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_right_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_right_autopilot_icon.png new file mode 100644 index 0000000000..cc2b18083d Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_right_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_switch_map_angle.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_switch_map_angle.png new file mode 100644 index 0000000000..3e1b96f3e3 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_switch_map_angle.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_wrong_autopilot_icon.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_wrong_autopilot_icon.png new file mode 100644 index 0000000000..0c8988acb3 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/bus_wrong_autopilot_icon.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/img_bus_status_bg.png b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/img_bus_status_bg.png new file mode 100644 index 0000000000..27cb9285d3 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable-xhdpi/img_bus_status_bg.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg.xml new file mode 100644 index 0000000000..a830539009 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg_check.png b/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg_check.png new file mode 100644 index 0000000000..28857974b5 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg_check.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg_nor.png b/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg_nor.png new file mode 100644 index 0000000000..f7d4f92c4b Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable/bus_autopilot_status_bg_nor.png differ diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_base_autopilot_status_icon_selector.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_base_autopilot_status_icon_selector.xml new file mode 100644 index 0000000000..94555d78cc --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_base_autopilot_status_icon_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_operation_status_bg.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_operation_status_bg.xml new file mode 100644 index 0000000000..753d85e3ec --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_operation_status_bg.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/modules/mogo-module-adas/src/main/res/drawable/module_adas_timer_bg_shape.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_panel_anchor_bkg.xml similarity index 53% rename from modules/mogo-module-adas/src/main/res/drawable/module_adas_timer_bg_shape.xml rename to OCH/mogo-och-bus/src/main/res/drawable/bus_panel_anchor_bkg.xml index 105edfe4de..38fc28d893 100644 --- a/modules/mogo-module-adas/src/main/res/drawable/module_adas_timer_bg_shape.xml +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_panel_anchor_bkg.xml @@ -1,4 +1,5 @@ - - + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_panel_bkg.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_panel_bkg.xml new file mode 100644 index 0000000000..204c5fc692 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_panel_bkg.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_station_green_dash_line.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_station_green_dash_line.xml new file mode 100644 index 0000000000..963cdf38be --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_station_green_dash_line.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_station_v_green_dash.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_station_v_green_dash.xml new file mode 100644 index 0000000000..376e0a472c --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_station_v_green_dash.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_switch_map_bg.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_switch_map_bg.xml new file mode 100644 index 0000000000..b34021d977 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_switch_map_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_yi_biao_pan_bg_nor.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_yi_biao_pan_bg_nor.xml new file mode 100644 index 0000000000..4bde0e73c1 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_yi_biao_pan_bg_nor.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/bus_yi_biao_pan_bg_speeding.xml b/OCH/mogo-och-bus/src/main/res/drawable/bus_yi_biao_pan_bg_speeding.xml new file mode 100644 index 0000000000..dea7a88bb6 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/drawable/bus_yi_biao_pan_bg_speeding.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-bus/src/main/res/drawable/img_bus_status_bg.9.png b/OCH/mogo-och-bus/src/main/res/drawable/img_bus_status_bg.9.png new file mode 100644 index 0000000000..0af2b9db73 Binary files /dev/null and b/OCH/mogo-och-bus/src/main/res/drawable/img_bus_status_bg.9.png differ diff --git a/OCH/mogo-och-bus/src/main/res/layout/bus_base_fragment.xml b/OCH/mogo-och-bus/src/main/res/layout/bus_base_fragment.xml new file mode 100644 index 0000000000..537a3d2dc9 --- /dev/null +++ b/OCH/mogo-och-bus/src/main/res/layout/bus_base_fragment.xml @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +