[fea]
[弱网module]
This commit is contained in:
yangyakun
2024-07-29 10:42:06 +08:00
parent b65c5b3b23
commit 55339202b1
334 changed files with 14865 additions and 0 deletions

1
OCH/shuttle_weaknet/driver/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,69 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
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"
kapt {
useBuildCache = false
arguments {
arg("AROUTER_MODULE_NAME", "shuttle"+project.getName())
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError false
}
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.kotlinstdlib
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.arouter
kapt rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.amapnavi3dmap
implementation rootProject.ext.dependencies.rxjava
implementation rootProject.ext.dependencies.rxandroid
implementation rootProject.ext.dependencies.androidxrecyclerview
compileOnly rootProject.ext.dependencies.recyclerviewadapterhelper
implementation project(":OCH:common:common")
implementation project(":OCH:common:data")
compileOnly project(":libraries:mogo-map")
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

@@ -0,0 +1,3 @@
GROUP=com.mogo.och
POM_ARTIFACT_ID=och-bus
VERSION_CODE=1

View File

@@ -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

View File

@@ -0,0 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.och.shuttle">
<application>
<activity android:name="com.mogo.och.shuttle.ui.BusSwitchLineActivity"
android:theme="@style/SwitchLineDialogStyle"
android:launchMode="singleTask"
android:screenOrientation="landscape" />
</application>
</manifest>

View File

@@ -0,0 +1,38 @@
package com.mogo.och.shuttle
import android.content.Context
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.och.shuttle.fragment.ShuttleFragment
import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.common.module.biz.provider.CommonServiceImpl
/**
* 网约车小巴业务实现入口
*
* @author tongchenfei
*/
@Route(path = OchCommonConst.SHUTTLE_DRIVER)
class ShuttleDriverProvider : CommonServiceImpl() {
private val TAG = ShuttleDriverProvider::class.java.simpleName
private var busFragment: ShuttleFragment?=null
override fun init(context: Context) {
d(SceneConstant.M_TAXI + TAG, "init")
}
override fun getFragment(): Fragment {
if(busFragment==null){
busFragment = ShuttleFragment()
}
return busFragment!!
}
override fun resetFragment() {
busFragment = null
}
}

View File

@@ -0,0 +1,23 @@
package com.mogo.och.shuttle.bean;
import com.mogo.commons.storage.SharedPrefsMgr;
import com.mogo.och.common.module.utils.DateTimeUtil;
/**
* 中止/结束任务请求
*/
public class BusCloseTaskRequest {
private String sn;
private int taskId;
private long writeVersion;
public BusCloseTaskRequest(int taskId) {
this.sn = SharedPrefsMgr.getInstance().getSn();
this.taskId = taskId;
this.writeVersion = DateTimeUtil.getCurrentTimeStamp();
}
public String getSn() {
return sn;
}
}

View File

@@ -0,0 +1,86 @@
package com.mogo.och.shuttle.bean;
/**
* @author congtaowang
* @since 2021/3/23
* <p>
* 小巴订单
*/
public class BusOrderBean {
/**
* orderNo number
* passengerPhone string 下单用户电话
* startStationId integer 开始站点
* startStationName string
* endStationId integer 结束站点
* endStationName string
*/
private String orderNo;
private String passengerPhone;
private int startStationId;//乘客上车点
private String startStationName;
private String endStationName;
private int endStationId;//乘客下车点
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
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 String getOrderNo() {
return orderNo;
}
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 "BusOrderBean{" +
"orderNo=" + orderNo +
", passengerPhone='" + passengerPhone + '\'' +
", startStationId=" + startStationId +
", startStationName='" + startStationName + '\'' +
", endStationName='" + endStationName + '\'' +
", endStationId=" + endStationId +
'}';
}
}

View File

@@ -0,0 +1,23 @@
package com.mogo.och.shuttle.bean;
import com.mogo.eagle.core.data.BaseData;
import java.util.List;
/**
* @author: wangmingjun
* @date: 2021/10/19
*/
public class BusOrdersResponse extends BaseData {
public Result data;
public static class Result{
public List<BusOrderBean> orders;
}
@Override
public String toString() {
return "BusOrdersResponse{" +
"data=" + data +
'}';
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.och.shuttle.bean;
import com.mogo.commons.storage.SharedPrefsMgr;
/**
* @author congtaowang
* @since 2021/3/22
*
* 根据车机行驶线路站点信息
*/
public class BusQueryLineStationsRequest {
private String sn;
public BusQueryLineStationsRequest() {
this.sn = SharedPrefsMgr.getInstance().getSn();
}
}

View File

@@ -0,0 +1,19 @@
package com.mogo.och.shuttle.bean;
import com.mogo.eagle.core.data.BaseData;
import java.util.List;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public class BusQueryLineTaskResponse extends BaseData {
public List<Result> data;
public static class Result {
public int id;
public long taskStartTime;
}
}

View File

@@ -0,0 +1,27 @@
package com.mogo.och.shuttle.bean;
import com.mogo.eagle.core.data.BaseData;
import java.util.List;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public class BusQueryLinesResponse extends BaseData {
public List<Result> data;
public static class Result {
public int lineId;//线路id
public String name;//线路名字
public int choose; // 1:绑定 2:未被绑定
public String startSiteName;//始发站名称
public String endSiteName;//终点名称
public boolean open;//true 打开状态 false
public boolean haveTask;
public List<BusQueryLineTaskResponse.Result> taskList;
}
}

View File

@@ -0,0 +1,20 @@
package com.mogo.och.shuttle.bean;
import com.mogo.commons.storage.SharedPrefsMgr;
import com.mogo.och.common.module.utils.DateTimeUtil;
/**
* @author: wangmingjun
* @date: 2021/10/18
*/
public class BusResetDrivingLineRequest {
public String sn;
public int taskId; //切换到的线路id
public long writeVersion; //更新时间戳
public BusResetDrivingLineRequest(int taskId) {
this.sn = SharedPrefsMgr.getInstance().getSn();
this.taskId = taskId;
this.writeVersion = DateTimeUtil.getCurrentTimeStamp();
}
}

View File

@@ -0,0 +1,28 @@
package com.mogo.och.shuttle.bean;
import com.mogo.eagle.core.data.BaseData;
import com.mogo.och.data.bean.BusRoutesResult;
/**
* 网约车小巴路线接口请求响应结果
*
* @author tongchenfei
*/
public class BusRoutesResponse extends BaseData {
private BusRoutesResult data;
public BusRoutesResult getResult() {
return data;
}
public void setResult(BusRoutesResult data) {
this.data = data;
}
@Override
public String toString() {
return "BusRoutesResponse{" +
"data=" + data +
'}';
}
}

View File

@@ -0,0 +1,26 @@
package com.mogo.och.shuttle.bean;
import com.mogo.commons.storage.SharedPrefsMgr;
/**
* @author congtaowang
* @since 2021/3/22
*
* 小巴车运营状态请求参数
*/
public class BusUpdateSiteStatusRequest {
public String sn;
public int taskId;
public int seq;//站点序号
public int siteId;//站点id
public long writeVersion; //更新时间戳
public BusUpdateSiteStatusRequest(int taskId,int siteId,int seq, long writeVersion) {
this.sn = SharedPrefsMgr.getInstance().getSn();
this.seq = seq;
this.siteId = siteId;
this.taskId = taskId;
this.writeVersion = writeVersion;
}
}

View File

@@ -0,0 +1,36 @@
package com.mogo.och.shuttle.bean;
import com.mogo.commons.storage.SharedPrefsMgr;
/**
* 查询下车乘客请求参数
*
* @author tongchenfei
*/
public class QueryLeaveAwayPassengersRequest {
private String sn;
private int seq; //站点在线路中的序号
private int siteId; //站点id
public QueryLeaveAwayPassengersRequest(int seq, int siteId) {
this.sn = SharedPrefsMgr.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;
}
}

View File

@@ -0,0 +1,60 @@
package com.mogo.och.shuttle.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 {
/**
* orderNo: 订单no
* orderStatus: 订单状态
* orderType订单类型0及时1预约
* bookingTime预计用车时间
* businessType订单运营类型 9:taxi10:bus
* startSiteId 起点站点id
* userPhone: 乘客联系方式
* startSitePoint开始站点坐标
* startSiteAddr开始地址
* endSiteId结束站点id
* endSitePoint结束站点坐标
* carNumber车牌号
* createTime: 创建时间
* startTime开始时间
* startSiteGcjPoint高精坐标
* endSiteGcjPoint
*/
//todo 目前是需要乘客电话来通知乘客下车 目前后台没有乘客信息userPhone
public String orderNo;
public int orderStatus;
public int orderType;
public long bookingTime;
public int businessType;
public int startSiteId;
public String passengerPhone;
public List<Double> startSitePoint;
public String startSiteAddr;
public int endSiteId;
public List<Double> endSitePoint;
public String carNumber;
public long createTime;
public long startTime;
public List< Double > startSiteGcjPoint;
public List< Double > endSiteGcjPoint;
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.och.shuttle.bean;
import com.mogo.eagle.core.data.BaseData;
import java.util.List;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public class WriteOffCountResponse extends BaseData {
public Integer data;
}

View File

@@ -0,0 +1,15 @@
package com.mogo.och.shuttle.bean;
import java.io.Serializable;
/**
* @author: wangmingjun
* @date: 2022/9/23
*/
public class WriteOffPassenger implements Serializable {
public String phone;
public String orderNo;
public String ticketName;
public int passengerSize;
public long writeOffTime;
}

View File

@@ -0,0 +1,11 @@
package com.mogo.och.shuttle.callback;
/**
* Created on 2021/9/8
*
* Model->Presenter回调ADAS相关自动驾驶状态回调到达终点等等
*/
public interface IBusADASStatusCallback {
//自驾返回失败
void onStartAdasFailure();
}

View File

@@ -0,0 +1,15 @@
package com.mogo.och.shuttle.callback;
import com.mogo.eagle.core.data.map.MogoLocation;
/**
* Created on 2021/9/10
*
* Model->Presenter回调状态控制器监听accOn、adas ui show、voice ui show、push ui show、v2x ui show等等
*/
public interface IBusControllerStatusCallback {
// 自车定位
void onCarLocationChanged(MogoLocation location);
//开始开启自动驾驶
void startOpenAutopilot();
}

View File

@@ -0,0 +1,14 @@
package com.mogo.och.shuttle.callback;
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse;
import com.mogo.och.shuttle.bean.BusQueryLinesResponse;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public interface IBusLinesCallback {
void onBusLinesChange(BusQueryLinesResponse lines);
void onChangeLineIdSuccess();
void onBusLineTasks(BusQueryLineTaskResponse o, int position,boolean autoRefresh);
}

View File

@@ -0,0 +1,23 @@
package com.mogo.och.shuttle.callback;
import com.mogo.och.data.bean.BusStationBean;
import java.util.List;
/**
* @author: wangmingjun
* @date: 2021/10/22
*/
public interface IRefreshBusStationsCallback {
void updateBusTaskStatus(String lineName,String lintTime,
List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived);
/**
* 结束清理一遍、选择任务后清理一遍
*/
void clearBusStationsMarkers();
void updateEmptyUi();
}

View File

@@ -0,0 +1,9 @@
package com.mogo.och.shuttle.callback;
/**
* @author: wangmingjun
* @date: 2021/10/22
*/
public interface ISlidePannelHideCallback {
void hideSlidePanel();
}

View File

@@ -0,0 +1,60 @@
package com.mogo.och.shuttle.constant
import com.mogo.commons.debug.DebugConfig
/**
* Created on 2021/12/6
*/
class BusConst {
companion object {
// OCH arouter 路由path
const val PATH = "/driver/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_15S = 15 * 1000L
const val LOOP_PERIOD_1S = 1 * 1000L
const val LOOP_DELAY = 100L
// 下发给MEC轨迹信息间隔时间 10秒
const val LOOP_PERIOD_10S = 10 * 1000L
// 尝试下发给MEC轨迹最多10次
const val LOOP_SEND_TRAJ_TIMES = 10
//起点UUID
const val BUS_START_MAP_MAKER = "bus_start_map_maker";
//终点UUID
const val BUS_END_MAP_MAKER = "bus_end_map_maker";
/**
* 订单起终点Marker类型
*/
const val TYPE_MARKER_BUS_ORDER = "TYPE_MARKER_BUS_ORDER"
const val TIMER_START_AUTOPILOT_INTERVAL = 20 * 1000L
//围栏到站 暂定10米
const val ARRIVE_AT_END_STATION_DISTANCE = 10
// 轮询
const val LOOP_PASSENGER_5S = 5 * 1000L
const val LOOP_PASSENGER_2S = 2 * 1000L
const val LOOP_PASSENGER_1S = 1 * 1000L
const val LOOP_DELAY_500 = 500L
const val DELAY_10S = 10 * 1000L
}
}

View File

@@ -0,0 +1,558 @@
package com.mogo.och.shuttle.fragment;
import static com.mogo.och.shuttle.constant.BusConst.TIMER_START_AUTOPILOT_INTERVAL;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.Group;
import androidx.core.content.ContextCompat;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.mvp.IView;
import com.mogo.commons.mvp.MvpFragment;
import com.mogo.commons.mvp.Presenter;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.data.config.HdMapBuildConfig;
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager;
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager;
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxBubbleView;
import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxButtonView;
import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxListView;
import com.mogo.eagle.core.function.smp.view.SmallMapView;
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.map.MogoMap;
import com.mogo.map.uicontroller.IMogoMapUIController;
import com.mogo.och.common.module.utils.ResourcesUtils;
import com.mogo.och.shuttle.R;
import com.mogo.och.shuttle.view.BizMapView;
import com.mogo.och.data.bean.BusRoutesResult;
import com.mogo.och.shuttle.model.OrderModel;
import com.mogo.och.shuttle.view.SlidePanelView;
import com.mogo.och.common.module.utils.SoundPoolHelper;
import org.greenrobot.eventbus.EventBus;
/**
* 网约车基础Fragment主要负责布局通用界面处理站点面板和通话面板互斥情况
* <p>
* 部分业务放在了此处处理
*
* @author tongchenfei
*/
public abstract class BaseShuttleTabFragment<V extends IView, P extends Presenter<V>> extends MvpFragment<V, P> {
private static final String TAG = "BaseBusTabFragment";
protected SlidePanelView slidePanelView;
private RelativeLayout ctvAutopilotStatus;
private ImageView ctvAutopilotStatusIv;
private TextView ctvAutopilotStatusTv;
protected TextView tvArrived;
private FrameLayout flStationPanelContainer;
private BizMapView mapBizView;
private Group groupTestPanel;
protected SmallMapView smallMapView;
//消息盒子
private DriverMsgBoxButtonView viewDriverMsgBoxButton;
private DriverMsgBoxListView viewDriverMsgBoxList;
private DriverMsgBoxBubbleView viewDriverMsgBoxBubble;
private ObjectAnimator autopilotLoadingAnimator;
public boolean isAnimateRunning = false;
/**
* 滑动按钮触发的事件
*/
private final SlidePanelView.OnSlidePanelMoveToEndListener onSlideToEndListener = () -> {
// 此处做一个代理,处理一下共有情况
if (getSlidePanelOnEndListener() != null) {
getSlidePanelOnEndListener().moveToEnd();
}
};
@Override
protected int getLayoutId() {
return R.layout.shuttle_base_fragment;
}
@Override
protected void initViews() {
mapBizView = findViewById(R.id.mapBizView);
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);
tvArrived = findViewById(R.id.module_mogo_och_arrived_tv);
FrameLayout flSpeed = findViewById(R.id.fl_speed);
if (flSpeed != null) {
CallerDevaToolsManager.INSTANCE.attachAutopilotBeforeLaunchView(flSpeed.getContext(), flSpeed);
}
LayoutInflater.from(getContext()).inflate(getStationPanelViewId(), flStationPanelContainer);
slidePanelView.setOnSlidePanelMoveToEndListener(onSlideToEndListener);
updateSwitchMapIcon();
initListener();
setAutopilotBtnStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),
CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false, 0));
ctvAutopilotStatus.setOnClickListener(new OnPreventFastClickListener() {
@Override
public void onClickImpl(View v) {
restartAutopilot();
}
});
// 模拟 不可自动驾驶目前场景是刚开机adas还未和工控机连接
findViewById(R.id.btnAutopilotDisable).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE)
);
// 模拟 可自动驾驶,工控机连接正常,且处于人工干预状态
findViewById(R.id.btnAutopilotEnable).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE)
);
// 模拟 自动驾驶能力,自动驾驶中,可能是停车,可能是行进,但是是机器在处理车的前进后退,不是人
findViewById(R.id.btnAutopilotRunning).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING)
);
findViewById(R.id.btnAutopilotPingxing).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING)
);
// 模拟 自动驾驶网约车回调数据
findViewById(R.id.btnAutopilotArrive).setOnClickListener(view ->
debugArrivedStation()
);
tvArrived.setOnClickListener(view -> {
onArriveStation();
});
//消息盒子
viewDriverMsgBoxButton = findViewById(R.id.viewDriverMsgBoxButton);
viewDriverMsgBoxList = findViewById(R.id.viewDriverMsgBoxList);
viewDriverMsgBoxBubble = findViewById(R.id.viewDriverMsgBoxBubble);
viewDriverMsgBoxButton.setClickListener(show -> {
if(show){
viewDriverMsgBoxList.setVisibility(View.VISIBLE);
viewDriverMsgBoxList.notifyData();
viewDriverMsgBoxBubble.setVisibility(View.GONE);
viewDriverMsgBoxBubble.isShowData(false);
}else{
viewDriverMsgBoxList.setVisibility(View.GONE);
viewDriverMsgBoxBubble.setVisibility(View.VISIBLE);
viewDriverMsgBoxBubble.isShowData(true);
}
});
smallMapView = findViewById(R.id.smallMapView);
}
@Override
protected void initViews(Bundle savedInstanceState) {
super.initViews(savedInstanceState);
mapBizView.onCreate(savedInstanceState);
smallMapView.onCreateView(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
mapBizView.onResume();
smallMapView.onResume();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container
, @Nullable Bundle savedInstanceState) {
EventBus.getDefault().register(this);
return super.onCreateView(inflater, container, savedInstanceState);
}
protected abstract void onArriveStation();
private void updateSwitchMapIcon() {
IMogoMapUIController mapUIController = CallerMapUIServiceManager.INSTANCE.getMapUIController(MogoMap.DEFAULT);
if(mapUIController!=null){
if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
mapUIController.changeCurrentIcon(R.raw.m2);
HdMapBuildConfig.currentCarVrIconRes = R.raw.m2;
}else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
mapUIController.changeCurrentIcon(R.raw.xiaoba);
HdMapBuildConfig.currentCarVrIconRes = R.raw.xiaoba;
}
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
mapBizView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapBizView.onLowMemory();
}
@Override
public void onPause() {
super.onPause();
mapBizView.onPause();
smallMapView.onPause();
}
@Override
public void onDestroyView() {
mapBizView.onDestroy();
if(smallMapView != null){
smallMapView.onDestroy();
}
super.onDestroyView();
CallerAutopilotRecordListenerManager.INSTANCE.removeListener(TAG);
EventBus.getDefault().unregister(this);
}
/**
* 测试到站
*/
protected abstract void debugArrivedStation();
private void initListener() {
}
/**
* 展示滑动按钮
*
* @param text 指定的文字
*/
public void showSlidePanel(String text) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
slidePanelView.setText(text);
slidePanelView.setVisibility(View.VISIBLE);
}
}, UiThreadHandler.MODE.QUEUE);
setArrivedClikable(false);
}
/**
* 设置进站按钮状态
*
* @param isClickable
*/
public void setArrivedClikable(boolean isClickable) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
tvArrived.setEnabled(isClickable);
if (isClickable) {
tvArrived.setTextColor(ContextCompat.getColor(AbsMogoApplication.getApp(),R.color.bus_white));
} else {
tvArrived.setTextColor(ContextCompat.getColor(AbsMogoApplication.getApp(),R.color.bus_arrived_btn_un_clickable_color));
}
}
}, UiThreadHandler.MODE.QUEUE);
}
/**
* 隐藏滑动按钮
*/
public void hideSlidePanel() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
slidePanelView.setVisibility(View.GONE);
}
}, UiThreadHandler.MODE.QUEUE);
}
public void playDI() {
SoundPoolHelper.getSoundPoolHelper().playSoundWithRedId(getContext(), R.raw.bus_di);
}
/**
* 改变自动驾驶状态
*
* @param autopilotStatus 0:不可用 1:可用状态 2:自动驾驶中
*/
public void onAutopilotStatusChanged(int autopilotStatus,boolean canStartAuto) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
changeAutopilotBtnView(autopilotStatus, isAnimateRunning,canStartAuto);
}
}, UiThreadHandler.MODE.QUEUE);
}
public void setAutopilotBtnStatus(int autopilotStatus,boolean canStartAuto) {
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE == autopilotStatus) {//0不可用
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_disable));
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_runnig_tv));
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon);
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_start_fail);
} else {
ctvAutopilotStatusTv.setTextColor(AbsMogoApplication.getApp().getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_ic_autopilot);
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE == autopilotStatus) { //1可用
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_runnig_tv));
if(canStartAuto){
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_press);
}else {
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_disable));
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon);
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_start_fail);
}
} else if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING == autopilotStatus) {
ctvAutopilotStatusTv.setText(R.string.bus_loading_autopilot_runnig_tv);
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_in_autopilot);
} else if (IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING
== autopilotStatus){
ctvAutopilotStatusTv.setText(R.string.bus_pingxing_driver);
ctvAutopilotStatus.setClickable(false);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_pxjs);
}
}
}
public void updateAutopilotStatus(int autopilotStatus) {
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
== autopilotStatus) {//2 running
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_right_autopilot_icon);
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_success_tv));
// ctvAutopilotStatus.setSelected(false);
ctvAutopilotStatus.setClickable(false);
} else {
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_wrong_autopilot_icon);
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_failure_tv));
ctvAutopilotStatus.setClickable(false);
// ctvAutopilotStatus.setSelected(false);
}
UiThreadHandler.postDelayed(new Runnable() {
@Override
public void run() {
setAutopilotBtnStatus(autopilotStatus,CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false, 0));
}
}, 1000);
}
private void changeAutopilotBtnView(int autopilotStatus, boolean isAnimateRunning,boolean canStartAuto) {
if (isAnimateRunning && IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
!= autopilotStatus) {
// 主动开启自动驾驶中不为2为0、1则继续loading
return;
}
if (isAnimateRunning) {
stopAnimAndUpdateBtnStatus();
} else {
setAutopilotBtnStatus(autopilotStatus,canStartAuto);
}
}
public void stopAnimAndUpdateBtnStatus() {
stopAutopilotAnimation();
updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState());
}
/**
* 隐藏【自动驾驶】按钮
*/
public void hideAutopilotBiz() {
}
/**
* 展示【自动驾驶】按钮
*/
public void showAutopilotBiz() {
}
public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() {
return null;
}
/**
* 获取站点面板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() {
isAnimateRunning = true;
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_tv));
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatus.setClickable(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();//动画开始
startingAutoApilotCountDown();
}
private void startingAutoApilotCountDown() {
//10s 若自动驾驶没有开启,则结束动画
UiThreadHandler.postDelayed(new Runnable() {
@Override
public void run() { //未启动成功做处理
if (isAnimateRunning) {// 只判断动画是否在进行,根据自动驾驶当前状态去设置自动驾驶状态
stopAutopilotAnimation();
updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState());
}
}
}, TIMER_START_AUTOPILOT_INTERVAL);
}
/**
* 停止自动驾驶中间动画
*/
protected void stopAutopilotAnimation() {
if (autopilotLoadingAnimator != null) {
autopilotLoadingAnimator.end();
ctvAutopilotStatusIv.clearAnimation();
autopilotLoadingAnimator = null;
isAnimateRunning = false;
}
}
// /**
// * 迈速表实时更新
// *
// * @param newSpeed
// */
// public void updateSpeedView(float newSpeed) {
// int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值
// if (mTrafficDataView != null) {
// mTrafficDataView.updateSpeedWithValue(speed);
// }
// }
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* bus调试面板打开关闭
*/
public void debugTestBar() {
if (groupTestPanel.getVisibility() == View.VISIBLE) {
groupTestPanel.setVisibility(View.GONE);
} else {
groupTestPanel.setVisibility(View.VISIBLE);
}
}
/**
* Bus调试信息线路、轨迹等信息
* <p>
* START
*/
private View busTestBar;
private TextView lineIdTV;
private TextView lineNameTV;
private TextView trajMd5TV;
private TextView stopMd5TV;
private TextView trajMd5DPQPTV;
private TextView stopMd5DPQPTV;
public void showHideTestBar() {
if (busTestBar == null) {
busTestBar = findViewById(R.id.module_mogo_och_bus_test_bar);
lineIdTV = findViewById(R.id.bus_test_bar_current_line_id);
lineNameTV = findViewById(R.id.bus_test_bar_current_line_name);
trajMd5TV = findViewById(R.id.bus_test_bar_current_traj_md5);
stopMd5TV = findViewById(R.id.bus_test_bar_current_stop_md5);
trajMd5DPQPTV = findViewById(R.id.bus_test_bar_current_traj_md5_dpqp);
stopMd5DPQPTV = findViewById(R.id.bus_test_bar_current_stop_md5_dpqp);
}
if (busTestBar.getVisibility() == View.VISIBLE) {
busTestBar.setVisibility(View.GONE);
} else {
BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult();
lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId())));
lineNameTV.setText("lineName:" + (routesResult == null ? "" : routesResult.getName()));
trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5));
stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5));
trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP));
stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP));
busTestBar.setVisibility(View.VISIBLE);
}
}
public void updateBusTestBarInfo() {
if (busTestBar != null && busTestBar.getVisibility() == View.VISIBLE) {
BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult();
lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId())));
lineNameTV.setText("lineName:" + (routesResult == null ? "" : routesResult.getName()));
trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5));
stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5));
trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP));
stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP));
}
}
/**
* END
*/
}

View File

@@ -0,0 +1,551 @@
package com.mogo.och.shuttle.fragment;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
import static com.mogo.map.MogoMap.DEFAULT;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Group;
import androidx.annotation.Nullable;
import com.mogo.commons.storage.SharedPrefsMgr;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.data.temp.EventLogout;
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.map.CallerMapUIServiceManager;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant;
import com.mogo.eagle.core.utilcode.util.ActivityUtils;
import com.mogo.eagle.core.utilcode.util.ToastUtils;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.map.overlay.IMoGoOverlayManager;
import com.mogo.map.overlay.core.Level;
import com.mogo.map.overlay.point.Point;
import com.mogo.och.common.module.utils.ResourcesUtils;
import com.mogo.och.shuttle.R;
import com.mogo.och.data.bean.BusStationBean;
import com.mogo.och.shuttle.constant.BusConst;
import com.mogo.och.shuttle.presenter.BusPresenter;
import com.mogo.och.shuttle.ui.BusStationCommonItem;
import com.mogo.och.shuttle.ui.BusSwitchLineActivity;
import com.mogo.och.shuttle.view.SlidePanelView;
import com.mogo.och.common.module.utils.BlinkAnimationUtil;
import com.mogo.och.common.module.utils.OCHThreadPoolManager;
import com.mogo.och.common.module.utils.QRUtilsKt;
import com.mogo.och.common.module.wigets.BindQRCodeDialog;
import com.mogo.och.common.module.wigets.MarqueeTextView;
import com.mogo.och.common.module.wigets.OCHCommitDialog;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import java.util.Objects;
import me.jessyan.autosize.utils.AutoSizeUtils;
/**
* 网约车小巴界面
*
* @author tongchenfei
*/
public class ShuttleFragment extends BaseShuttleTabFragment<ShuttleFragment, BusPresenter>
implements SlidePanelView.OnSlidePanelMoveToEndListener, View.OnClickListener {
public static final String TAG = "BusFragment";
private TextView mSwitchLine; //切换路线
private MarqueeTextView mLineName;
private TextView mTaskTime;
private Group groupStationsPanel;
private ConstraintLayout noDataView;
private BusStationBean startStation = null;
private BusStationBean endStation = null;
private BusStationCommonItem firstStationItem;
private BusStationCommonItem secondStationItem;
private BusStationCommonItem thirdStationItem;
@Override
public String getTagName() {
return "BusFragment";
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onDestroyView() {
if (mPresenter != null) {
mPresenter.onDestroy(this);
}
IMoGoOverlayManager overlayManager = CallerMapUIServiceManager.INSTANCE.getOverlayManager();
if(overlayManager!=null) {
overlayManager.removeAllLines();
overlayManager.removeAllPoints();
}
super.onDestroyView();
}
@Override
protected void initViews() {
super.initViews();
mSwitchLine = findViewById(R.id.switch_line_btn);
mSwitchLine.setTag(0);
mLineName = findViewById(R.id.module_och_bus_line_name);
firstStationItem = findViewById(R.id.bus_panel_first_station);
secondStationItem = findViewById(R.id.bus_panel_second_station);
thirdStationItem = findViewById(R.id.bus_panel_third_station);
mTaskTime = findViewById(R.id.bus_task_time_tv);
groupStationsPanel = findViewById(R.id.group_stations_panel);
noDataView = findViewById(R.id.no_line_data_view);
CallerLogger.d(M_BUS + TAG, "initView: " + CallerAutoPilotStatusListenerManager.INSTANCE.getState());
// 初始化的时候设置 UI 按钮状态
showAutopilotBiz();
mSwitchLine.setOnClickListener(this);
mLineName.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
showHideTestBar();
return false;
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void changeOverview(EventLogout eventLogout){
if (eventLogout.getMessgae() == EventLogout.LOGOUT_TYPE){
CallerLogger.d(M_BUS + TAG,"changeOverview Event消息去登出");
mPresenter.logout();
}else if (eventLogout.getMessgae() == EventLogout.SHOW_QR_TYPE){ //显示二维码
CallerLogger.d(M_BUS + TAG,"changeOverview Event qrcodesn = "
+ SharedPrefsMgr.getInstance().getSn());
String qrUrl = String.format(FunctionBuildConfig.urlJson.getBindDriverQRUrl(),
SharedPrefsMgr.getInstance().getSn());
Bitmap bmQr = QRUtilsKt.createQRCodeWithPicture(
BitmapFactory.decodeResource(getResources(), R.drawable.icon_qr_center_logo)
,qrUrl, AutoSizeUtils.dp2px(getContext(),340f),
AutoSizeUtils.dp2px(getContext(),340f),true);
if (bmQr != null){
BindQRCodeDialog.Builder builder = new BindQRCodeDialog.Builder();
builder.title(getString(R.string.bind_driver_qr_title))
.cancelStr(getString(R.string.qr_cancel))
.qrBm(bmQr).build(getContext()).show();
}else {
CallerLogger.d(M_BUS + TAG,"bmQr = null ");
}
}
}
@Override
protected void onArriveStation() {
mPresenter.onAutopilotArriveAtStation(null);
mPresenter.arriveStation(null,"点击进站触发进站操作");
}
@Override
protected void debugArrivedStation() {
mPresenter.onAutopilotArriveAtStation(null);
mPresenter.arriveStation(null,"点击debug进站按钮触发进站操作");
}
@NonNull
@Override
protected BusPresenter createPresenter() {
return new BusPresenter(this);
}
@Override
public void onResume() {
super.onResume();
}
public void hideStationsPanel(){
groupStationsPanel.setVisibility(View.GONE);
noDataView.setVisibility(View.VISIBLE);
}
public void showStationsPanel(){
groupStationsPanel.setVisibility(View.VISIBLE);
noDataView.setVisibility(View.GONE);
}
public void updateLineEmptyUI(){
setArrivedClikable(false);
showOrHideSwitchLineBtn(true);
hideStationsPanel();
hideSlidePanel();
resetStationBlinkAnim();
}
private void resetStationBlinkAnim() {
BlinkAnimationUtil.clearAnimation(firstStationItem.getCircleImageView());
BlinkAnimationUtil.clearAnimation(secondStationItem.getCircleImageView());
BlinkAnimationUtil.clearAnimation(thirdStationItem.getCircleImageView());
}
public void updateBusTaskStatus(String lineName, String lineTime,
List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived){
if (getActivity() == null) {
return;
}
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if (stationList == null) {
// 获取小巴数据失败
return;
}
showStationsPanel();
showOrHideSwitchLineBtn(false);
mLineName.setText(lineName);
mTaskTime.setText(getString(R.string.bus_line_time_tag)+ lineTime);
// 渲染小巴路线数据
updateBusStationStatus(stationList,arrivingOrArrivedIndex,isArrived);
}
},UiThreadHandler.MODE.QUEUE);
}
private void updateBusStationStatus(List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
startStation = stationList.get(0);
endStation = stationList.get(stationList.size() - 1);
if (arrivingOrArrivedIndex == stationList.size() - 1 && isArrived){
//切换路线和结束路线按钮切换
showSlidePanel("单程结束");
setOrRemoveMapMaker(false, BusConst.BUS_END_MAP_MAKER, endStation.getLat()
, endStation.getLon(),R.raw.end_marker);
}else if (arrivingOrArrivedIndex == 0 && isArrived){
showSlidePanel("滑动出发");
setOrRemoveMapMaker(true, BusConst.BUS_START_MAP_MAKER,
startStation.getLat(), startStation.getLon(),R.raw.star_marker);
setOrRemoveMapMaker(true, BusConst.BUS_END_MAP_MAKER,
endStation.getLat(), endStation.getLon(),R.raw.end_marker);
}else{
if (isArrived){
// 重置滑动按钮文字
showSlidePanel("滑动出发");
}
setOrRemoveMapMaker(false, BusConst.BUS_START_MAP_MAKER, startStation.getLat()
, startStation.getLon(),R.raw.star_marker);
setOrRemoveMapMaker(true, BusConst.BUS_END_MAP_MAKER, endStation.getLat()
, endStation.getLon(),R.raw.end_marker);
}
if (stationList.size() > 2){ //只有两个站点
updateMoreThanTwoStationsUI(stationList,arrivingOrArrivedIndex,isArrived);
}else {
updateTwoStationsUI(stationList,arrivingOrArrivedIndex,isArrived);
}
updateBusTestBarInfo();
}
/**
* 有两个以上站点的路线
* @param stationList
* @param arrivingOrArrivedIndex
* @param isArrived
*/
private void updateMoreThanTwoStationsUI(List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
secondStationItem.setStationTag("");
secondStationItem.showOrHideStationArrowBg(true);
thirdStationItem.setStationTag("");
secondStationItem.setVisibility(View.VISIBLE);
thirdStationItem.showOrHideStationArrowBg(false);
if (arrivingOrArrivedIndex == 0 || arrivingOrArrivedIndex -1 == 0
|| (arrivingOrArrivedIndex -2 == 0 && stationList.size() == 3)){
firstStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_start));
}else {
firstStationItem.setStationTag("");
}
if (arrivingOrArrivedIndex + 1 == stationList.size() - 1 || arrivingOrArrivedIndex == stationList.size() - 1
|| (arrivingOrArrivedIndex == 0 && arrivingOrArrivedIndex + 2 == stationList.size() - 1)){ //确认是否显示 "终"
thirdStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_end));
}else {
thirdStationItem.setStationTag("");
}
//圆点: 0:灰色 过站 1绿色 到站或者即将到站 2蓝色未到站
if (arrivingOrArrivedIndex == 0 && isArrived){
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
firstStationItem.setStationName(stationList.get(0).getName());
secondStationItem.setStationName(stationList.get(1).getName());
thirdStationItem.setStationName(stationList.get(2).getName());
firstStationItem.setStationPointBg(1);
secondStationItem.setStationPointBg(2);
thirdStationItem.setStationPointBg(2);
firstStationItem.setStationArrowBg(2);
secondStationItem.setStationArrowBg(2);
}else if (arrivingOrArrivedIndex == stationList.size() - 1){
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
firstStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -2).getName());
secondStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -1).getName());
thirdStationItem.setStationName(stationList.get(arrivingOrArrivedIndex).getName());
firstStationItem.setStationPointBg(0);
secondStationItem.setStationPointBg(0);
thirdStationItem.setStationPointBg(1);
firstStationItem.setStationArrowBg(0);
if (isArrived){
secondStationItem.setStationArrowBg(0);
}else {
secondStationItem.setStationArrowBg(1);
}
}else {
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
firstStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -1).getName());
secondStationItem.setStationName(stationList.get(arrivingOrArrivedIndex).getName());
thirdStationItem.setStationName(stationList.get(arrivingOrArrivedIndex + 1).getName());
firstStationItem.setStationPointBg(0);
secondStationItem.setStationPointBg(1);
thirdStationItem.setStationPointBg(2);
secondStationItem.setStationArrowBg(2);
if (isArrived){
firstStationItem.setStationArrowBg(0);
}else {
firstStationItem.setStationArrowBg(1);
}
}
}
/**
* 只有两个站点的路线
* @param stationList
* @param arrivingOrArrivedIndex
* @param isArrived
*/
private void updateTwoStationsUI(List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
secondStationItem.setVisibility(View.GONE);
secondStationItem.showOrHideStationArrowBg(false);
thirdStationItem.showOrHideStationArrowBg(false);
firstStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_start));
thirdStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_end));
firstStationItem.setStationName(stationList.get(0).getName());
thirdStationItem.setStationName(stationList.get(1).getName());
//圆点: 0:灰色 过站 1绿色 到站或者即将到站 2蓝色未到站
if (arrivingOrArrivedIndex == 0 && isArrived){//到站
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
firstStationItem.setStationPointBg(1);
firstStationItem.setStationArrowBg(2);
thirdStationItem.setStationPointBg(0);
}else {
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
if (isArrived){ //到终点
firstStationItem.setStationPointBg(0);
firstStationItem.setStationArrowBg(0);
thirdStationItem.setStationPointBg(1);
}else { //到终点途中
firstStationItem.setStationPointBg(0);
firstStationItem.setStationArrowBg(1);
thirdStationItem.setStationPointBg(1);
}
}
}
private void showOrHideSwitchLineBtn(boolean isShow) {
if (isShow){//显示切换路线
mSwitchLine.setTag(0);
mSwitchLine.setText(ResourcesUtils.getString(R.string.bus_switch_line_btn));
}else {//显示结束路线
mSwitchLine.setTag(1);
mSwitchLine.setText(ResourcesUtils.getString(R.string.bus_close_line_btn));
}
}
public void hideOchBus() {
// tvNotice.setVisibility(View.GONE);
}
@Override
public int getStationPanelViewId() {
return R.layout.shuttle_fragment_och;
}
@Override
public void restartAutopilot() {
if (!isAnimateRunning) {
mPresenter.restartAutopilot();
}
}
@Override
public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() {
return this;
}
@Override
public void moveToEnd() {
// 开启自动驾驶到下一站
if (isAnimateRunning){
stopAutopilotAnimation();
}
mPresenter.autoDriveToNextStation();
}
/**
* 设置自动驾驶可用状态
*/
public void onAutopilotEnableChange(boolean isEnable) {
if (isEnable) {
showAutopilotBiz();
} else {
hideAutopilotBiz();
}
}
public void clearBusStationsMarkers(){
CallerLogger.d(M_BUS + TAG,"clearBusStationsMarkers()");
if (null != startStation) {
setOrRemoveMapMaker(false, BusConst.BUS_START_MAP_MAKER, startStation.getLat()
, startStation.getLon(),R.raw.star_marker);
}
if (null != endStation) {
setOrRemoveMapMaker(false, BusConst.BUS_END_MAP_MAKER, endStation.getLat()
, endStation.getLon(),R.raw.end_marker);
}
//清除鹰眼右下角小地图轨迹
CallerLogger.d(SceneConstant.M_BUS, "clearBusStationsMarkers --------->");
smallMapView.clearPolyline();
}
/**
* 绘制地图起点终点
*
* @param isAdd
* @param uuid
*/
private void setOrRemoveMapMaker(boolean isAdd, String uuid, double lat, double longi,int resourceId) {
if (isAdd) {
Runnable setMapMarkerRunnable = () -> {
CallerLogger.d(M_BUS + "setMapMaker= "+Thread.currentThread().getName(),
uuid + "=latitude=" + lat + ",longitude=" + longi);
Point.Options.Builder builder = new Point.Options.Builder(BusConst.TYPE_MARKER_BUS_ORDER, Level.MAP_MARKER)
.setId(uuid)
.anchor(0.5f, 0.5f)
.set3DMode(true)
.isUseGps(true)
.controlAngle(false)
.icon3DRes(resourceId)
.latitude(lat)
.longitude(longi);
IMoGoOverlayManager overlayManager = CallerMapUIServiceManager.INSTANCE.getOverlayManager();
if (overlayManager != null) {
overlayManager.showOrUpdatePoint(builder.build(),DEFAULT);
}
};
OCHThreadPoolManager.getsInstance().execute(setMapMarkerRunnable);
}else {
Runnable removeMapMarkerRunnable = () -> {
CallerLogger.d(M_BUS + "RemoveMapMaker="+Thread.currentThread().getName(),
uuid+"=latitude="+lat+",longitude="+longi);
Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getOverlayManager()).removePoint(uuid);
};
OCHThreadPoolManager.getsInstance().execute(removeMapMarkerRunnable);
}
}
@Override
public void debugAutoPilotStatus(int status) {
mPresenter.debugAutoPilotStatus(status);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.switch_line_btn) {//切换路线条件: 自动驾驶过程中点击则toast提示自动驾驶中不可切换路线
//本次行程未结束不支持切换路线。点击则toast提示当前行程未完成不可切换路线
if (CallerAutoPilotStatusListenerManager.INSTANCE.getState()
== IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
ToastUtils.showLong(ResourcesUtils.getString(R.string.bus_switch_line_btn_warning1));
return;
}
if ((int)mSwitchLine.getTag() == 0){//切换路线
Intent intent = new Intent(getContext(), BusSwitchLineActivity.class);
ActivityUtils.startActivity(intent);
}else {//结束任务
OCHCommitDialog.Builder builder = new OCHCommitDialog.Builder();
OCHCommitDialog closeLineConfirmDialog = builder
.title(getString(R.string.bus_dialog_title))
.tips(getString(R.string.bus_dialog_tips))
.confirmStr(getString(R.string.bus_dialog_confirm))
.cancelStr(getString(R.string.bus_dialog_cancel))
.build(getContext());
closeLineConfirmDialog.setClickListener(new OCHCommitDialog.ClickListener() {
@Override
public void confirm() {
mPresenter.abortTask();
}
@Override
public void cancel() {
closeLineConfirmDialog.dismiss();
}
});
closeLineConfirmDialog.show();
}
}
}
}

View File

@@ -0,0 +1,148 @@
package com.mogo.och.shuttle.model;
import android.content.Context;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.storage.SharedPrefsMgr;
import com.mogo.eagle.core.utilcode.util.NetworkUtils;
import com.mogo.eagle.core.utilcode.util.ToastUtils;
import com.mogo.och.shuttle.R;
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse;
import com.mogo.och.shuttle.bean.BusQueryLinesResponse;
import com.mogo.och.shuttle.bean.BusRoutesResponse;
import com.mogo.och.shuttle.callback.IBusLinesCallback;
import com.mogo.och.shuttle.net.OrderServiceManager;
import com.mogo.och.shuttle.ui.BusSwitchLineActivity;
import com.mogo.och.common.module.network.OchCommonServiceCallback;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public class BusLineModel {
private static volatile BusLineModel sInstance;
private Context mContext;
private IBusLinesCallback mBusLinesCallback;
public static BusLineModel getInstance() {
if ( sInstance == null ) {
synchronized ( BusLineModel.class ) {
if ( sInstance == null ) {
sInstance = new BusLineModel();
}
}
}
return sInstance;
}
private BusLineModel() {
}
public void init() {
mContext = AbsMogoApplication.getApp();
}
public void setBusLinesCallback(IBusLinesCallback callback){
mBusLinesCallback = callback;
}
public void queryBusLines(){
OrderServiceManager.queryBusLines(mContext, new OchCommonServiceCallback<BusQueryLinesResponse>() {
@Override
public void onSuccess(BusQueryLinesResponse data) {
if (null == data && mBusLinesCallback != null) {
mBusLinesCallback.onBusLinesChange(null);
return;
}
if (mBusLinesCallback != null){
mBusLinesCallback.onBusLinesChange(data);
}
}
@Override
public void onError() {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
} else {
ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
}
}
@Override
public void onFail(int code, String failMsg) {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort("网络异常,请稍后重试");
}else {
ToastUtils.showShort("查询所有绑定路线失败:"+failMsg);
}
}
});
}
/**
* 通过线路id 查询线路排班表
* @param lineId 线路ID
* @param position 位置
*/
public void queryBusLineTasksById(int lineId, int position,boolean autoRefresh){
OrderServiceManager.queryBusTaskByLineId(mContext, String.valueOf(lineId),new OchCommonServiceCallback<BusQueryLineTaskResponse>() {
@Override
public void onSuccess(BusQueryLineTaskResponse data) {
if (null == data && mBusLinesCallback != null) {
mBusLinesCallback.onBusLineTasks(null,position,autoRefresh);
return;
}
if (mBusLinesCallback != null){
mBusLinesCallback.onBusLineTasks(data,position,autoRefresh);
}
}
@Override
public void onError() {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
} else {
ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
}
}
@Override
public void onFail(int code, String failMsg) {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort("网络异常,请稍后重试");
}else {
ToastUtils.showShort("查询所有绑定路线失败:"+failMsg);
}
}
});
}
public void commitSwitchLineId(int taskId,int lineId){
OrderServiceManager.switchLine(mContext,taskId, new OchCommonServiceCallback<BusRoutesResponse>() {
@Override
public void onSuccess(BusRoutesResponse o) {
SharedPrefsMgr.getInstance().putInt(BusSwitchLineActivity.LASTCOMMITLINEID,lineId);
if (mBusLinesCallback != null){
mBusLinesCallback.onChangeLineIdSuccess();
}
}
@Override
public void onError() {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort(mContext.getString(R.string.network_error_tip));
} else {
ToastUtils.showShort(mContext.getString(R.string.request_error_tip));
}
}
@Override
public void onFail(int code, String failMsg) {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort("网络异常,请稍后重试");
}else {
ToastUtils.showShort("选择任务失败:"+failMsg);
}
}
});
}
}

View File

@@ -0,0 +1,218 @@
package com.mogo.och.shuttle.model
import com.elegant.network.utils.GsonUtil
import com.mogo.aicloud.services.socket.IMogoOnMessageListener
import com.mogo.commons.AbsMogoApplication
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.data.msgbox.MsgBoxType
import com.mogo.eagle.core.data.msgbox.V2XMsg
import com.mogo.eagle.core.function.api.telematic.IReceivedMsgListener
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager.saveMsgBox
import com.mogo.eagle.core.function.call.telematic.CallerTelematicListenerManager
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.i
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.util.GsonUtils
import com.mogo.och.shuttle.bean.WriteOffCountResponse
import com.mogo.och.shuttle.bean.WriteOffPassenger
import com.mogo.och.shuttle.net.OrderServiceManager
import com.mogo.och.shuttle.util.ShuttleVoiceManager
import com.mogo.och.common.module.manager.socket.lan.bean.BaseDPMsg
import com.mogo.och.common.module.manager.socket.lan.bean.DPMsgType
import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffDevicesMsg
import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffMsg
import com.mogo.och.common.module.manager.socket.cloud.OCHSocketMessageManager
import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.manager.loop.LoopInfo
import io.reactivex.Observable
import io.reactivex.ObservableEmitter
import io.reactivex.ObservableOnSubscribe
import io.reactivex.schedulers.Schedulers
object TicketModel : IReceivedMsgListener, IMogoOnMessageListener<WriteOffPassenger> {
private val TAG = "TicketModel"
private val SELECTWRITEOFFCOUNT = "SELECTWRITEOFFCOUNT"
private var emitterMain: ObservableEmitter<Int>?=null
private val observable = Observable.create(ObservableOnSubscribe<Int> { emitter -> emitterMain = emitter })
init {
//监听乘客屏发来的消息
CallerTelematicListenerManager.addListener(TAG, this)
OCHSocketMessageManager.registerSocketMessageListener( //监听核销乘客
OCHSocketMessageManager.msgWriteOffPassengerType,
this
)
}
fun load(){
BizLoopManager.setLoopFunction(
SELECTWRITEOFFCOUNT, LoopInfo(3,
TicketModel::selectWriteOffCount,scheduler = Schedulers.io()))
}
// 收到局域网的核验信息
override fun onReceivedMsg(type: Int, byteArray: ByteArray) {
if (OchCommonConst.BUSINESS_STRING == type) {
d(SceneConstant.M_BUS + TAG, "局域网核验"+String(byteArray))
val msg = GsonUtils.fromJson(String(byteArray), BaseDPMsg::class.java)
if (msg != null) {
if (msg.type == DPMsgType.TYPE_WRITEOFF_INFO.type) {
val writeOffMsg = GsonUtils.fromJson(String(byteArray), WriteOffMsg::class.java)
receiveWrteOffInfo(writeOffMsg)
} else if (msg.type == DPMsgType.TYPE_WRITEOFF_DEVICES_INFO.type) {
val writeOffMsg = GsonUtils.fromJson(String(byteArray), WriteOffDevicesMsg::class.java)
receiveWrteOffDevicesInfo(writeOffMsg)
}
}
}
}
override fun target(): Class<WriteOffPassenger> {
return WriteOffPassenger::class.java
}
// 收到服务器的核验信息
override fun onMsgReceived(passenger: WriteOffPassenger?) {
//进行播报
i(SceneConstant.M_BUS + TAG, "后台socket 核验:passenger = " + GsonUtil.jsonFromObject(passenger))
if(passenger==null||passenger.passengerSize==0){
return
}
playPassenger(
passenger.passengerSize,
passenger.phone ?: "",
passenger.ticketName?:"",
passenger.orderNo?:""
)
selectWriteOffCount()
}
private fun selectWriteOffCount(){
val busRoutesResult = OrderModel.getInstance().busRoutesResult
val busNextStation = OrderModel.getInstance().busNextStation
if(busRoutesResult==null||busNextStation==null){
emitterMain?.onNext(0)
d(SceneConstant.M_BUS + TAG, "线路或者站点未空:${busRoutesResult}----${busNextStation}")
return
}
OrderServiceManager.queryBusTaskByLineId(AbsMogoApplication.getApp(),
"${busRoutesResult.taskId}",
"${busNextStation.siteId}",
object : OchCommonServiceCallback<WriteOffCountResponse> {
override fun onSuccess(data: WriteOffCountResponse?) {
data?.data?.let {
emitterMain?.onNext(it)
d(SceneConstant.M_BUS + TAG, "${busNextStation.name}核销人数:${it}")
}
}
override fun onFail(code: Int, msg: String?) {
}
})
}
fun getWriteOffCountObservable():Observable<Int>{
return observable
}
private fun receiveWrteOffInfo(writeOffMsg: WriteOffMsg?) {
if(writeOffMsg!=null) {
if (writeOffMsg.isScuccess != null) {
if (writeOffMsg.isScuccess == true) { // 核验成功
if(writeOffMsg.ticketSize==null||writeOffMsg.ticketSize==0){
return
}
// playPassenger(
// writeOffMsg.ticketSize?:0,
// writeOffMsg.phone ?: "",
// writeOffMsg.ticketName ?: "",
// writeOffMsg.orderNo?:""
// )
} else { // 核验失败
ShuttleVoiceManager.writeOffFaile("验票失败,${writeOffMsg.failedReason ?: ""}")
saveMsgBox(
MsgBoxBean(
MsgBoxType.V2X, V2XMsg(
EventTypeEnumNew.TYPE_ABNORMAL_VERIFICATION.poiType,
writeOffMsg.failedReason ?: "",
EventTypeEnumNew.TYPE_ABNORMAL_VERIFICATION.tts,
""
)
)
)
}
}
}
}
private fun receiveWrteOffDevicesInfo(writeOffMsg: WriteOffDevicesMsg) {
if (writeOffMsg.isConnectScanner != null) {
val reason = if (writeOffMsg.reason == null) "" else writeOffMsg.reason!!
if (writeOffMsg.isConnectScanner==true) { // 链接成功
saveMsgBox(
MsgBoxBean(
MsgBoxType.V2X,
V2XMsg(
EventTypeEnumNew.TYPE_DEVICE_STATUS_NORMAL.poiType,
reason,
EventTypeEnumNew.TYPE_DEVICE_STATUS_NORMAL.tts,
""
)
)
)
} else { // 核验失败
saveMsgBox(
MsgBoxBean(
MsgBoxType.V2X,
V2XMsg(
EventTypeEnumNew.TYPE_DEVICE_STATUS_ABNORMAL.poiType,
reason,
EventTypeEnumNew.TYPE_DEVICE_STATUS_ABNORMAL.tts,
""
)
)
)
}
}
}
private fun playPassenger(ticketSize: Int,phone:String,ticketName:String,orderNo:String) {
if (ticketSize > 1) { //多人播报 "x人" ---》x人核验通过
OrderModel.getInstance().sendWriteOffNumToClient(ticketSize.toString() + "人核验通过")
} else { //是 1 播放 "滴" 2022.11.09 改为: "核验通过"
OrderModel.getInstance().sendWriteOffNumToClient("核验通过")
}
ShuttleVoiceManager.writeOffCount(ticketSize)
var tempPhone = phone
if (tempPhone.length > 8) {
//截取电话号码前三位
val phoneNumPre = tempPhone.substring(0, 3)
//截取电话号码后四位
val phoneNumFix = tempPhone.substring(7)
tempPhone = "$phoneNumPre****$phoneNumFix"
}
val content = "${ticketSize}$ticketName $tempPhone"
saveMsgBox(MsgBoxBean(
MsgBoxType.V2X,
V2XMsg(
EventTypeEnumNew.TYPE_VERIFICATION_SUCCESSFUL.poiType,
content,
EventTypeEnumNew.TYPE_VERIFICATION_SUCCESSFUL.tts,
""
)
)
)
}
}

View File

@@ -0,0 +1,115 @@
package com.mogo.och.shuttle.net;
import com.mogo.eagle.core.data.BaseData;
import com.mogo.och.shuttle.bean.BusCloseTaskRequest;
import com.mogo.och.shuttle.bean.BusOrdersResponse;
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse;
import com.mogo.och.shuttle.bean.BusQueryLinesResponse;
import com.mogo.och.shuttle.bean.BusQueryLineStationsRequest;
import com.mogo.och.shuttle.bean.BusRoutesResponse;
import com.mogo.och.shuttle.bean.QueryLeaveAwayPassengersRequest;
import com.mogo.och.shuttle.bean.QueryLeaveAwayPassengersResponse;
import com.mogo.och.shuttle.bean.BusResetDrivingLineRequest;
import com.mogo.och.shuttle.bean.BusUpdateSiteStatusRequest;
import com.mogo.och.shuttle.bean.WriteOffCountResponse;
import io.reactivex.Observable;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Query;
/**
* 小巴车相关接口
*
* @author tongchenfei
* <p>
* wiki: http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48970072
*/
public interface IBascApiService {
/**
* 查询当前运行任务
*
* @param request 请求参数
* @return 接口返回数据
*/
@Headers( {"Content-Type:application/json;charset=UTF-8"} )
@POST( "/och-shuttle-cabin/api/business/v1/driver/lineDataWithDriver/query" )
Observable<BusRoutesResponse> queryBusRoutes(@Header ("appId") String appId, @Header("ticket") String ticket, @Body BusQueryLineStationsRequest request);
/**
* @param request 请求参数{"destLine":1,"sn":"F803EB2046PZD00229"} 这个接口是重置bus线路的 不是重置线路中站点的
* @return 返回值是重置后的车站列表
* 开始路线
*/
@Headers( {"Content-Type:application/json;charset=UTF-8"} )
@POST( "/och-shuttle-cabin/api/flow/v1/driver/startTask" )
Observable<BusRoutesResponse> switchLine(@Header ("appId") String appId, @Header("ticket") String ticket, @Body BusResetDrivingLineRequest request);
/**
* 离站,通知服务器
* @param request
* @return
*/
@Headers({"Content-Type:application/json;charset=UTF-8"})
@POST("/och-shuttle-cabin/api/flow/v1/driver/leave")
Observable<BaseData> leaveStation(@Header ("appId") String appId, @Header("ticket") String ticket, @Body BusUpdateSiteStatusRequest request);
/**
* 到站 更新到站信息
* @param request
* @return
*/
@Headers({"Content-type:application/json;charset=UTF-8"})
@POST("/och-shuttle-cabin/api/flow/v1/driver/arrive")
Observable<BaseData> arriveSiteStation(@Header ("appId") String appId,@Header("ticket") String ticket,@Body BusUpdateSiteStatusRequest request);
/**
* 查询车辆配置的所有路线
* @param appId
* @param ticket
* @param sn
* @return
*/
@GET("/och-shuttle-cabin/api/business/v1/driver/bindLine/query")
Observable<BusQueryLinesResponse> queryBusLines(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("sn") String sn);
/**
* 查询线路的任务
* @param appId
* @param ticket
* @param lineId 线路id
* @return
*/
@GET("/och-shuttle-cabin/api/business/v1/driver/task/query")
Observable<BusQueryLineTaskResponse> queryBusTaskByLineId(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("lineId") String lineId);
/**
* 中止任务
* @param appId
* @param ticket
* @param data
* @return
*/
@POST("/och-shuttle-cabin/api/flow/v1/driver/abortTask")
Observable<BaseData> abortTask(@Header ("appId") String appId, @Header("ticket") String ticket, @Body BusCloseTaskRequest data);
/**
* 任务正常跑完结束
* @param appId
* @param ticket
* @param data
* @return
*/
@Headers( {"Content-type:application/json;charset=UTF-8"} )
@POST("/och-shuttle-cabin/api/flow/v1/driver/endTask")
Observable<BaseData> endTask(@Header ("appId") String appId, @Header("ticket") String ticket, @Body BusCloseTaskRequest data);
@Headers( {"Content-type:application/json;charset=UTF-8"} )
@GET("och-shuttle-cabin/api/business/v1/task/writeOffCount")
Observable<WriteOffCountResponse> writeOffCount(@Header ("appId") String appId, @Header("ticket") String ticket, @Query("taskId") String taskId, @Query("siteId") String siteId);
}

View File

@@ -0,0 +1,195 @@
package com.mogo.och.shuttle.net
import android.content.Context
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.eagle.core.data.BaseData
import com.mogo.eagle.core.network.MoGoRetrofitFactory
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.common.module.network.OchCommonSubscribeImpl
import com.mogo.och.common.module.network.interceptor.transformIoTry
import com.mogo.och.common.module.network.interceptor.transformTry
import com.mogo.och.shuttle.bean.BusCloseTaskRequest
import com.mogo.och.shuttle.bean.BusOrdersResponse
import com.mogo.och.shuttle.bean.BusQueryLineStationsRequest
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse
import com.mogo.och.shuttle.bean.BusQueryLinesResponse
import com.mogo.och.shuttle.bean.BusResetDrivingLineRequest
import com.mogo.och.shuttle.bean.BusRoutesResponse
import com.mogo.och.shuttle.bean.BusUpdateSiteStatusRequest
import com.mogo.och.shuttle.bean.QueryLeaveAwayPassengersRequest
import com.mogo.och.shuttle.bean.QueryLeaveAwayPassengersResponse
import com.mogo.och.shuttle.bean.WriteOffCountResponse
/**
* @author: wangmingjun
* @date: 2021/10/20
*/
object OrderServiceManager {
private val mService: IBascApiService = MoGoRetrofitFactory.getInstance(OchCommonConst.getShuttleUrl()).create(
IBascApiService::class.java
)
/**
* 查询小巴车当前任务
* @param context
* @param callback
*/
@JvmStatic
fun queryBusRoutes(context: Context, callback: OchCommonServiceCallback<BusRoutesResponse>?) {
//获取当前高德坐标
mService.queryBusRoutes(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
BusQueryLineStationsRequest()
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "queryBusRoutes"))
}
/**
* 重置线路站点
* @param context
* @param taskId
* @param callback
*/
@JvmStatic
fun switchLine(
context: Context,
taskId: Int,
callback: OchCommonServiceCallback<BusRoutesResponse>?
) {
mService.switchLine(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
BusResetDrivingLineRequest(taskId)
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "switchLine"))
}
/**
* 中断当前任务
* @param context
* @param taskId
* @param callback
*/
@JvmStatic
fun abortTask(context: Context, taskId: Int, callback: OchCommonServiceCallback<BaseData>?) {
mService.abortTask(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
BusCloseTaskRequest(taskId)
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "abortTask"))
}
/**
* 正常结束任务
* @param context
* @param taskId
* @param callback
*/
@JvmStatic
fun endTask(context: Context, taskId: Int, callback: OchCommonServiceCallback<BaseData>?) {
mService.endTask(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
BusCloseTaskRequest(taskId)
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "endTask"))
}
/**
* 离站上报
* @param context
* @param seq
* @param siteId
* @param callback
*/
@JvmStatic
fun leaveStation(
context: Context,
seq: Int,
siteId: Int,
taskId: Int,
writeVersion: Long,
callback: OchCommonServiceCallback<BaseData>?
) {
mService.leaveStation(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
BusUpdateSiteStatusRequest(taskId, siteId, seq,writeVersion)
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "leaveStation"))
}
/**
* 到站更新站点状态
* @param context
* @param seq
* @param siteId
* @param callback
*/
@JvmStatic
fun arriveSiteStation(
context: Context, seq: Int, siteId: Int, taskId: Int, writeVersion: Long,
callback: OchCommonServiceCallback<BaseData>?
) {
mService.arriveSiteStation(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
BusUpdateSiteStatusRequest(taskId, siteId, seq, writeVersion)
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "arriveSiteStation"))
}
@JvmStatic
fun queryBusLines(context: Context, callback: OchCommonServiceCallback<BusQueryLinesResponse>?) {
mService.queryBusLines(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
SharedPrefsMgr.getInstance().sn
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "queryBusLines"))
}
@JvmStatic
fun queryBusTaskByLineId(
context: Context,
lineId: String?,
callback: OchCommonServiceCallback<BusQueryLineTaskResponse>?
) {
mService.queryBusTaskByLineId(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
lineId
)
.transformTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "queryBusLines"))
}
@JvmStatic
fun queryBusTaskByLineId(
context: Context,
taskId: String?,
siteId: String?,
callback: OchCommonServiceCallback<WriteOffCountResponse>?
) {
mService.writeOffCount(
MoGoAiCloudClientConfig.getInstance().serviceAppId,
SharedPrefsMgr.getInstance().token,
taskId,
siteId
)
.transformIoTry()
.subscribe(OchCommonSubscribeImpl(context, callback, "writeOffCount"))
}
}

View File

@@ -0,0 +1,115 @@
package com.mogo.och.shuttle.presenter;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.mvp.Presenter;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse;
import com.mogo.och.shuttle.bean.BusQueryLinesResponse;
import com.mogo.och.shuttle.callback.IBusLinesCallback;
import com.mogo.och.shuttle.model.BusLineModel;
import com.mogo.och.shuttle.model.OrderModel;
import com.mogo.och.shuttle.ui.BusSwitchLineView;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public class BusLinePresenter extends Presenter<BusSwitchLineView> implements IBusLinesCallback {
private Disposable subscribe;
public BusLinePresenter(BusSwitchLineView view) {
super(view);
BusLineModel.getInstance().init();
OrderModel.getInstance().init();
}
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
super.onCreate(owner);
initListener();
}
private void initListener() {
BusLineModel.getInstance().setBusLinesCallback(this);
}
@Override
public void onBusLinesChange(BusQueryLinesResponse lines) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onBusLinesChange(lines);
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void onChangeLineIdSuccess() {
OrderModel.getInstance().clearBusStationDatas();
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onChangeLineIdSuccess();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
public void queryBusLines(){
BusLineModel.getInstance().queryBusLines();
}
public void queryBusLineTasks(int lineId, int position,boolean close){
if(subscribe!=null&&!subscribe.isDisposed()){
subscribe.dispose();
}
if(close){
return;
}
BusLineModel.getInstance().queryBusLineTasksById(lineId,position,false);
subscribe = Observable.interval(3, TimeUnit.MINUTES).subscribe(aLong -> {
BusLineModel.getInstance().queryBusLineTasksById(lineId,position,true);
});
}
public void commitSwitchLineId(int taskId,int lineId){
BusLineModel.getInstance().commitSwitchLineId(taskId,lineId);
}
public void removeListener(){
BusLineModel.getInstance().setBusLinesCallback(null);
}
public void queryBusRoutes(){
OrderModel.getInstance().queryBusRoutes();
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
super.onDestroy(owner);
if(subscribe!=null&&!subscribe.isDisposed()){
subscribe.dispose();
}
}
@Override
public void onBusLineTasks(BusQueryLineTaskResponse o, int position,boolean autoRefresh) {
if(mView!=null) {
mView.onBusLineTasks(o,position,autoRefresh);
}
}
}

View File

@@ -0,0 +1,327 @@
package com.mogo.och.shuttle.presenter;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.mvp.Presenter;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
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.CallerAutoPilotControlManager;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.eagle.core.utilcode.util.DateTimeUtils;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.common.module.biz.login.LoginStatusEnum;
import com.mogo.och.common.module.manager.autopilot.autopilot.ArrivedStation;
import com.mogo.och.common.module.manager.autopilot.autopilot.IOchAutopilotStatusListener;
import com.mogo.och.common.module.manager.autopilot.autopilot.OchAutoPilotStatusListenerManager;
import com.mogo.och.data.bean.BusStationBean;
import com.mogo.och.shuttle.callback.IBusADASStatusCallback;
import com.mogo.och.shuttle.callback.IBusControllerStatusCallback;
import com.mogo.och.shuttle.callback.IRefreshBusStationsCallback;
import com.mogo.och.shuttle.callback.ISlidePannelHideCallback;
import com.mogo.och.shuttle.fragment.ShuttleFragment;
import com.mogo.och.shuttle.model.OrderModel;
import com.mogo.och.shuttle.util.BusTrajectoryManager;
import com.mogo.och.common.module.biz.login.ILoginCallback;
import com.mogo.och.common.module.biz.login.LoginStatusManager;
import com.mogo.och.common.module.manager.autopilot.OCHAdasAbilityManager;
import java.util.ArrayList;
import java.util.List;
import mogo_msg.MogoReportMsg;
/**
* 网约车小巴
*
* @author tongchenfei
*/
public class BusPresenter extends Presenter<ShuttleFragment>
implements IRefreshBusStationsCallback, ISlidePannelHideCallback
, IOchAutopilotStatusListener, IBusControllerStatusCallback, ILoginCallback, IBusADASStatusCallback {
private static final String TAG = "BusPresenter";
private final List<BusStationBean> mStationList = new ArrayList<>();
private int mCurrentStation = 0;
public BusPresenter(ShuttleFragment view) {
super(view);
//2021.11.1 鹰眼架构整合由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口
OrderModel.getInstance().init();
OCHAdasAbilityManager.getInstance().init(AbsMogoApplication.getApp());
}
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
super.onCreate(owner);
initModelListener();
OrderModel.getInstance().queryBusCacheRoutes();
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
super.onDestroy(owner);
OrderModel.getInstance().release();
releaseListener();
}
public void initModelListener() {
OrderModel.getInstance().setRefreshBusStationsCallback(this);
OrderModel.getInstance().setSlidePanelHideCallback(this);
OrderModel.getInstance().setControllerStatusCallback(this);
OrderModel.getInstance().setAdasStatusCallback(this);
OchAutoPilotStatusListenerManager.INSTANCE.addListener(TAG,this);
LoginStatusManager.INSTANCE.addListener(TAG,this);
}
public void releaseListener() {
OrderModel.getInstance().setRefreshBusStationsCallback(null);
OrderModel.getInstance().setSlidePanelHideCallback(null);
OrderModel.getInstance().setControllerStatusCallback(null);
OrderModel.getInstance().setAdasStatusCallback(null);
OCHAdasAbilityManager.getInstance().release();
OchAutoPilotStatusListenerManager.INSTANCE.removeListener(TAG);
LoginStatusManager.INSTANCE.removeListener(TAG);
}
public void abortTask() {
OrderModel.getInstance().abortTask();
}
public void autoDriveToNextStation() {
OrderModel.getInstance().autoDriveToNextStation();
}
public void restartAutopilot() {
if (OrderModel.getInstance().isGoingToNextStation()){
OrderModel.getInstance().restartAutopilot();
}
}
// 登出
public void logout() {
OrderModel.getInstance().logout();
}
@Override
public void updateBusTaskStatus(String lineName,String lineTime,
List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
mStationList.clear();
mStationList.addAll(stationList);
if (arrivingOrArrivedIndex == 0 || isArrived){
mCurrentStation = arrivingOrArrivedIndex;
}else {
mCurrentStation = arrivingOrArrivedIndex -1;
}
CallerLogger.d(M_BUS + "BusOrderModel =", " mCurrentStation =" + mCurrentStation);
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.updateBusTaskStatus(lineName,lineTime,
stationList, arrivingOrArrivedIndex, isArrived);
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void updateEmptyUi() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.updateLineEmptyUI();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void clearBusStationsMarkers() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.clearBusStationsMarkers();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void hideSlidePanel() {
if (mView != null) {
mView.hideSlidePanel();
mView.setArrivedClikable(true);
}
}
@Override
public void onAutopilotArriveAtStation(ArrivedStation arrivedStation) {
CallerLogger.e( M_BUS + TAG, "行程日志-onAutopilotArriveAtStation arrive");
arriveStation(arrivedStation,"底盘触发进站");
}
public void arriveStation(ArrivedStation arrivedStation,String type){
OrderModel.getInstance().onArriveAt(arrivedStation,type);
}
@Override
public void onAutopilotStatusResponse(int state) {
switch (state) {
case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE:
case IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING:
case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE:
if (FunctionBuildConfig.isDemoMode
&& (
(mCurrentStation >= 0 && mCurrentStation <= mStationList.size() - 1)
&& OrderModel.getInstance().isGoingToNextStation()
)
) {
CallerLogger.d(M_BUS + "BusOrderModel=", "有美化功能");
return;
}
// 改变UI自动驾驶状态
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotStatusChanged(state, CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0));
}
}
}, UiThreadHandler.MODE.QUEUE);
break;
case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING:
OrderModel.getInstance().triggerStartServiceEvent(
OrderModel.getInstance().isRestartAutopilot(), true);
// 改变UI自动驾驶状态
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotStatusChanged(state, CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0));
}
}
}, UiThreadHandler.MODE.QUEUE);
break;
default:
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotEnableChange(false);
}
}
}, UiThreadHandler.MODE.QUEUE);
break;
}
}
@Override
public void onCarLocationChanged(MogoLocation location) {
// if (null != location) {
// runOnUIThread(() -> mView.updateSpeedView(location.getGnssSpeed()));
// }
}
@Override
public void startOpenAutopilot() {
//非美化模式下启动动画
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.startAutopilotAnimation();
}
}
}, UiThreadHandler.MODE.QUEUE);
//中间站点再次开启自驾时, 自动驾驶状态是2未改变 此次鹰眼底层不再返给业务,需优化按钮动画显示
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
== CallerAutoPilotStatusListenerManager.INSTANCE.getState()&&mView!=null){
mView.onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),
CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0));
}
}
private void runOnUIThread(Runnable executor) {
if (executor == null) {
return;
}
if (Looper.myLooper() != Looper.getMainLooper()) {
UiThreadHandler.post(executor);
} else {
executor.run();
}
}
/**
* 测试使用
*/
public void debugAutoPilotStatus(int status) {
onAutopilotStatusResponse(status);
}
@Override
public void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo, long lineId) {
BusTrajectoryManager.getInstance().onAutopilotGuardian(guardianInfo,lineId);
}
@Override
public void onStatusChange(LoginStatusEnum currentStatus) {
ILoginCallback.super.onStatusChange(currentStatus);
CallerLogger.d(M_BUS + TAG, " loginStatus =" + LoginStatusManager.isLogin());
if(LoginStatusManager.isLogin()){
// OrderModel.getInstance().queryBusRoutes();
OrderModel.getInstance().queryBusCacheRoutes();
}else {
BusTrajectoryManager.getInstance().stopTrajReqLoop();
BusTrajectoryManager.getInstance().stopTrajReqLoop();
clearBusStationsMarkers();
if(mView!=null) {
mView.hideSlidePanel();
}
OrderModel.getInstance().closeBeautificationMode();
}
}
@Override
public void onStartAdasFailure() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.stopAnimAndUpdateBtnStatus();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void canStartAutopilot(boolean canStart) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),canStart);
}
}
}, UiThreadHandler.MODE.QUEUE);
}
}

View File

@@ -0,0 +1,99 @@
package com.mogo.och.shuttle.ui
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.mogo.och.shuttle.R
import com.mogo.och.common.module.utils.BlinkAnimationUtil
import kotlinx.android.synthetic.main.shuttle_stations_common_item.view.*
/**
* @author: wangmingjun
* @date: 2022/9/15
*/
class BusStationCommonItem @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr){
init {
LayoutInflater.from(context).inflate(R.layout.shuttle_stations_common_item,this,true)
}
fun setStationName(name: String){
busStationNameTv.text = name
}
fun setStationNameColor(color: Int){
busStationNameTv.setTextColor(color)
}
fun setStationPointBg(type: Int) { // 0:灰色 过站 1绿色 到站或者即将到站 2蓝色未到站
BlinkAnimationUtil.clearAnimation(busCircleIv)
when (type) {
0 -> {
busCircleIvBg.visibility = GONE
busCircleIv.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_point_grey_bus
)
)
}
1 -> {
busCircleIvBg.visibility = VISIBLE
busCircleIv.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_point_green_bus
)
)
BlinkAnimationUtil.setAnimation(busCircleIv)
}
2 -> {
busCircleIvBg.visibility = GONE
busCircleIv.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_point_blue_bus
)
)
}
}
}
fun getCircleImageView() : ImageView{
return busCircleIv
}
fun setStationArrowBg(type: Int){// 0:灰色 过站 1绿色 前往下一站 2蓝色 未到站
when(type){
0 -> busArrowBg.setImageResource(R.drawable.icon_arrow_grey_bus)
1 -> busArrowBg.setImageResource(R.drawable.icon_arrow_green_bus)
2 -> busArrowBg.setImageResource(R.drawable.icon_arrow_blue_bus)
}
}
fun setStationTag(tag: String){ // 0起 1
if (tag.isNullOrEmpty()){
busTagTxt.visibility = GONE
}else{
busTagTxt.text = tag
busTagTxt.visibility = VISIBLE
}
}
fun showOrHideStationArrowBg(isShow:Boolean){
if (isShow){
busArrowBg.visibility = VISIBLE
}else{
busArrowBg.visibility = GONE
}
}
}

View File

@@ -0,0 +1,222 @@
package com.mogo.och.shuttle.ui
import android.graphics.Point
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mogo.commons.mvp.MvpActivity
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.och.shuttle.presenter.BusLinePresenter
import com.mogo.och.shuttle.ui.adapter.SwitchLineAdapter
import com.mogo.och.shuttle.bean.BusQueryLinesResponse
import com.mogo.och.shuttle.ui.adapter.OpenItemAnimator
import com.mogo.eagle.core.utilcode.mogo.view.SpacesItemDecoration
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.shuttle.R
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse
import java.util.ArrayList
/**
* @author: wangmingjun
* @date: 2022/2/8
*/
class BusSwitchLineActivity : MvpActivity<BusSwitchLineView?, BusLinePresenter?>(),
View.OnClickListener, BusSwitchLineView {
companion object{
const val LASTCOMMITLINEID = "lastcommitlineid"
}
private lateinit var mClose: ImageView
private lateinit var mNoDatasView: ConstraintLayout
private lateinit var mLinesListView: RecyclerView
private lateinit var mLineCommitBtn: TextView
private lateinit var mAdapter: SwitchLineAdapter
private lateinit var linearLayoutManager:LinearLayoutManager
private val mData: MutableList<BusQueryLinesResponse.Result> = ArrayList()
override fun getLayoutId(): Int {
return R.layout.shuttle_switch_line
}
override fun createPresenter(): BusLinePresenter {
return BusLinePresenter(this)
}
override fun initViews() {
initWH()
initView()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initDatas()
}
/**
* 初始化view
*/
private fun initView() {
mClose = findViewById(R.id.switch_line_close)
mClose.setOnClickListener(this)
mNoDatasView = findViewById(R.id.no_order_data_view)
mLineCommitBtn = findViewById(R.id.switch_line_btn_commit)
mLineCommitBtn.setOnClickListener(this)
mLinesListView = findViewById(R.id.switch_line_rv)
linearLayoutManager = LinearLayoutManager(this)
mLinesListView.setLayoutManager(linearLayoutManager)
mLinesListView.setItemAnimator(OpenItemAnimator())
mAdapter = SwitchLineAdapter(applicationContext, mData)
mLinesListView.addItemDecoration(
SpacesItemDecoration(
4
)
)
mLinesListView.setAdapter(mAdapter)
//设置item 点击事件
mAdapter.setOnLineItemClickListener(object : SwitchLineAdapter.LineItemClickListener{
override fun onItemClick(position: Int, close: Boolean) {
mPresenter?.queryBusLineTasks(mData[position].lineId, position, close)
}
})
}
/**
* 设置布局宽高
*/
private fun initWH() {
val window = window
val params = window.attributes
val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
val point = Point()
windowManager.defaultDisplay.getSize(point) //用于获取屏幕高度
params.width = (point.x * 0.375).toInt()
params.height = ViewGroup.LayoutParams.MATCH_PARENT
window.attributes = params
window.setGravity(Gravity.START or Gravity.BOTTOM)
}
/**
* 初始化数据
*/
private fun initDatas() {
mPresenter?.queryBusLines()
}
/**
* 查询返回绑定路线集合
* @param data
*/
override fun onBusLinesChange(data: BusQueryLinesResponse?) {
if (null == data) {
showNoData(true)
return
}
val lastCommitLineid = SharedPrefsMgr.getInstance().getInt(LASTCOMMITLINEID, -1)
if (data.data != null && data.data.size > 0) {
showNoData(false)
mData.clear()
mData.addAll(data.data)
mAdapter.notifyDataSetChanged()
if(lastCommitLineid>0){
mData.forEachIndexed { index, line ->
if(line.lineId==lastCommitLineid){
line.open = true
mPresenter?.queryBusLineTasks(line.lineId,index,false)
return
}
}
}
} else {
showNoData(true)
}
}
override fun onChangeLineIdSuccess() {
ToastUtils.showLong(resources.getString(R.string.bus_change_line_commit_tip_s))
mPresenter?.queryBusRoutes()
mAdapter.setOnLineItemClickListener(null)
mPresenter?.removeListener()
finish()
}
override fun onBusLineTasks(lineTaskInfo: BusQueryLineTaskResponse?, position: Int, autoRefresh:Boolean) {
val result = mData[position]
if (result.taskList == null) {
result.taskList = ArrayList()
}
if (lineTaskInfo == null) {
result.haveTask = true
// 打开操作
mAdapter.notifyItemChanged(position)
} else {
if (lineTaskInfo.data == null || lineTaskInfo.data.isEmpty()) {
result.haveTask = true
lineTaskInfo.data = ArrayList()
}
if (lineTaskInfo.data.size != result.taskList.size) { // 不相等有变动 重新赋值
result.taskList.clear()
result.taskList.addAll(lineTaskInfo.data)
if(autoRefresh) {
mAdapter.checkTaskId = -1
mAdapter.checkLineId = -1
lineTaskInfo.data.forEach {
if (it.id == mAdapter.checkTaskId) {
mAdapter.checkTaskId = it.id
mAdapter.checkLineId = result.lineId
}
}
}
// 打开操作
mAdapter.notifyItemChanged(position)
linearLayoutManager.stackFromEnd = (position==mData.size-1||position==mData.size-2)&&mData.size>6
mLinesListView.smoothScrollToPosition(position)
}else if(lineTaskInfo.data.isEmpty()){
mAdapter.notifyItemChanged(position)
}
}
}
/**
* 有无数据UI显示
* @param b
*/
private fun showNoData(b: Boolean) {
if (b) {
mLinesListView.visibility = View.GONE
mLineCommitBtn.visibility = View.GONE
mNoDatasView.visibility = View.VISIBLE
} else {
mLinesListView.visibility = View.VISIBLE
mLineCommitBtn.visibility = View.VISIBLE
mNoDatasView.visibility = View.GONE
}
}
override fun onClick(v: View) {
//关闭dialog
if (v.id == R.id.switch_line_close) {
finish()
return
}
//切换路线提交
if (v.id == R.id.switch_line_btn_commit) {
if(mAdapter.checkLineId!=-1&&mAdapter.checkTaskId!=-1){
mPresenter?.commitSwitchLineId(mAdapter.checkTaskId,mAdapter.checkLineId)
}else{
ToastUtils.showLong("请选择任务")
}
}
}
override fun onDestroy() {
mPresenter!!.removeListener()
super.onDestroy()
}
}

View File

@@ -0,0 +1,18 @@
package com.mogo.och.shuttle.ui;
import com.mogo.commons.mvp.IView;
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse;
import com.mogo.och.shuttle.bean.BusQueryLinesResponse;
/**
* @author: wangmingjun
* @date: 2022/2/10
*/
public interface BusSwitchLineView extends IView {
void onBusLinesChange(BusQueryLinesResponse data);
void onChangeLineIdSuccess();
void onBusLineTasks(BusQueryLineTaskResponse o, int position,boolean autoRefresh);
}

View File

@@ -0,0 +1,643 @@
package com.mogo.och.shuttle.ui.adapter;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewPropertyAnimator;
import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import java.util.ArrayList;
import java.util.List;
/**
* This implementation of {@link RecyclerView.ItemAnimator} provides basic
* animations on remove, add, and move events that happen to the items in
* a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
*
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
*/
public class OpenItemAnimator extends DefaultItemAnimator {
private static final boolean DEBUG = false;
private static TimeInterpolator sDefaultInterpolator;
private final ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList<>();
private final ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList<>();
private final ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
private final ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList<>();
ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList<>();
private static class MoveInfo {
public RecyclerView.ViewHolder holder;
public int fromX, fromY, toX, toY;
MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
this.holder = holder;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
private static class ChangeInfo {
public RecyclerView.ViewHolder oldHolder, newHolder;
public int fromX, fromY, toX, toY;
private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
this.oldHolder = oldHolder;
this.newHolder = newHolder;
}
ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
this(oldHolder, newHolder);
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
@Override
public String toString() {
return "ChangeInfo{"
+ "oldHolder=" + oldHolder
+ ", newHolder=" + newHolder
+ ", fromX=" + fromX
+ ", fromY=" + fromY
+ ", toX=" + toX
+ ", toY=" + toY
+ '}';
}
}
@Override
public void runPendingAnimations() {
boolean removalsPending = !mPendingRemovals.isEmpty();
boolean movesPending = !mPendingMoves.isEmpty();
boolean changesPending = !mPendingChanges.isEmpty();
boolean additionsPending = !mPendingAdditions.isEmpty();
if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
// nothing to animate
return;
}
// First, remove stuff
for (RecyclerView.ViewHolder holder : mPendingRemovals) {
animateRemoveImpl(holder);
}
mPendingRemovals.clear();
// Next, move stuff
if (movesPending) {
final ArrayList<MoveInfo> moves = new ArrayList<>(mPendingMoves);
mMovesList.add(moves);
mPendingMoves.clear();
Runnable mover = () -> {
for (MoveInfo moveInfo : moves) {
animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
moveInfo.toX, moveInfo.toY);
}
moves.clear();
mMovesList.remove(moves);
};
if (removalsPending) {
View view = moves.get(0).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
} else {
mover.run();
}
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
final ArrayList<ChangeInfo> changes = new ArrayList<>(mPendingChanges);
mChangesList.add(changes);
mPendingChanges.clear();
Runnable changer = () -> {
for (ChangeInfo change : changes) {
animateChangeImpl(change);
}
changes.clear();
mChangesList.remove(changes);
};
if (removalsPending) {
RecyclerView.ViewHolder holder = changes.get(0).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
} else {
changer.run();
}
}
// Next, add stuff
if (additionsPending) {
final ArrayList<RecyclerView.ViewHolder> additions = new ArrayList<>(mPendingAdditions);
mAdditionsList.add(additions);
mPendingAdditions.clear();
Runnable adder = () -> {
for (RecyclerView.ViewHolder holder : additions) {
animateAddImpl(holder);
}
additions.clear();
mAdditionsList.remove(additions);
};
if (removalsPending || movesPending || changesPending) {
long removeDuration = removalsPending ? getRemoveDuration() : 0;
long moveDuration = movesPending ? getMoveDuration() : 0;
long changeDuration = changesPending ? getChangeDuration() : 0;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = additions.get(0).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
} else {
adder.run();
}
}
}
@Override
public boolean animateRemove(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
mPendingRemovals.add(holder);
return true;
}
private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
mRemoveAnimations.add(holder);
animation.setDuration(getRemoveDuration()).alpha(0).setListener(
new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchRemoveStarting(holder);
}
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
view.setAlpha(1);
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateAdd(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
holder.itemView.setAlpha(0);
mPendingAdditions.add(holder);
return true;
}
void animateAddImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
mAddAnimations.add(holder);
animation.alpha(1).setDuration(getAddDuration())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchAddStarting(holder);
}
@Override
public void onAnimationCancel(Animator animator) {
view.setAlpha(1);
}
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateMove(final RecyclerView.ViewHolder holder, int fromX, int fromY,
int toX, int toY) {
final View view = holder.itemView;
fromX += (int) holder.itemView.getTranslationX();
fromY += (int) holder.itemView.getTranslationY();
resetAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
dispatchMoveFinished(holder);
return false;
}
if (deltaX != 0) {
view.setTranslationX(-deltaX);
}
if (deltaY != 0) {
view.setTranslationY(-deltaY);
}
mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
final View view = holder.itemView;
final int deltaX = toX - fromX;
final int deltaY = toY - fromY;
if (deltaX != 0) {
view.animate().translationX(0);
}
if (deltaY != 0) {
view.animate().translationY(0);
}
// TODO: make EndActions end listeners instead, since end actions aren't called when
// vpas are canceled (and can't end them. why?)
// need listener functionality in VPACompat for this. Ick.
final ViewPropertyAnimator animation = view.animate();
mMoveAnimations.add(holder);
animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchMoveStarting(holder);
}
@Override
public void onAnimationCancel(Animator animator) {
if (deltaX != 0) {
view.setTranslationX(0);
}
if (deltaY != 0) {
view.setTranslationY(0);
}
}
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchMoveFinished(holder);
mMoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
if (oldHolder == newHolder) {
// Don't know how to run change animations when the same view holder is re-used.
// run a move animation to handle position changes.
return animateMove(oldHolder, fromX, fromY, toX, toY);
}
final float prevTranslationX = oldHolder.itemView.getTranslationX();
final float prevTranslationY = oldHolder.itemView.getTranslationY();
final float prevAlpha = oldHolder.itemView.getAlpha();
resetAnimation(oldHolder);
int deltaX = (int) (toX - fromX - prevTranslationX);
int deltaY = (int) (toY - fromY - prevTranslationY);
// recover prev translation state after ending animation
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
if (newHolder != null) {
// carry over translation values
resetAnimation(newHolder);
newHolder.itemView.setTranslationX(-deltaX);
newHolder.itemView.setTranslationY(-deltaY);
newHolder.itemView.setAlpha(0);
}
mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
void animateChangeImpl(final ChangeInfo changeInfo) {
final RecyclerView.ViewHolder holder = changeInfo.oldHolder;
final View view = holder == null ? null : holder.itemView;
final RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
if (view != null) {
final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(
getChangeDuration());
mChangeAnimations.add(changeInfo.oldHolder);
oldViewAnim.translationX((float)(changeInfo.toX - changeInfo.fromX));
oldViewAnim.translationY((float)(changeInfo.toY - changeInfo.fromY));
oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
@Override
public void onAnimationEnd(Animator animator) {
oldViewAnim.setListener(null);
view.setAlpha(1);
view.setTranslationX(0);
view.setTranslationY(0);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
dispatchFinishedWhenDone();
}
}).start();
}
if (newView != null) {
final ViewPropertyAnimator newViewAnimation = newView.animate();
mChangeAnimations.add(changeInfo.newHolder);
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration())
.alpha(1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
@Override
public void onAnimationEnd(Animator animator) {
newViewAnimation.setListener(null);
newView.setAlpha(1);
newView.setTranslationX(0);
newView.setTranslationY(0);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
dispatchFinishedWhenDone();
}
}).start();
}
}
private void endChangeAnimation(List<ChangeInfo> infoList, RecyclerView.ViewHolder item) {
for (int i = infoList.size() - 1; i >= 0; i--) {
ChangeInfo changeInfo = infoList.get(i);
if (endChangeAnimationIfNecessary(changeInfo, item)) {
if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
infoList.remove(changeInfo);
}
}
}
}
private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
if (changeInfo.oldHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
}
if (changeInfo.newHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
}
}
private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, RecyclerView.ViewHolder item) {
boolean oldItem = false;
if (changeInfo.newHolder == item) {
changeInfo.newHolder = null;
} else if (changeInfo.oldHolder == item) {
changeInfo.oldHolder = null;
oldItem = true;
} else {
return false;
}
item.itemView.setAlpha(1);
item.itemView.setTranslationX(0);
item.itemView.setTranslationY(0);
dispatchChangeFinished(item, oldItem);
return true;
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
final View view = item.itemView;
// this will trigger end callback which should set properties to their target values.
view.animate().cancel();
// TODO if some other animations are chained to end, how do we cancel them as well?
for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
MoveInfo moveInfo = mPendingMoves.get(i);
if (moveInfo.holder == item) {
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item);
mPendingMoves.remove(i);
}
}
endChangeAnimation(mPendingChanges, item);
if (mPendingRemovals.remove(item)) {
view.setAlpha(1);
dispatchRemoveFinished(item);
}
if (mPendingAdditions.remove(item)) {
view.setAlpha(1);
dispatchAddFinished(item);
}
for (int i = mChangesList.size() - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
endChangeAnimation(changes, item);
if (changes.isEmpty()) {
mChangesList.remove(i);
}
}
for (int i = mMovesList.size() - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
for (int j = moves.size() - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
if (moveInfo.holder == item) {
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(i);
}
break;
}
}
}
for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i);
if (additions.remove(item)) {
view.setAlpha(1);
dispatchAddFinished(item);
if (additions.isEmpty()) {
mAdditionsList.remove(i);
}
}
}
// animations should be ended by the cancel above.
//noinspection PointlessBooleanExpression,ConstantConditions
if (mRemoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mRemoveAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mAddAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mAddAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mChangeAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mChangeAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mMoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mMoveAnimations list");
}
dispatchFinishedWhenDone();
}
private void resetAnimation(RecyclerView.ViewHolder holder) {
if (sDefaultInterpolator == null) {
sDefaultInterpolator = new ValueAnimator().getInterpolator();
}
holder.itemView.animate().setInterpolator(sDefaultInterpolator);
endAnimation(holder);
}
@Override
public boolean isRunning() {
return (!mPendingAdditions.isEmpty()
|| !mPendingChanges.isEmpty()
|| !mPendingMoves.isEmpty()
|| !mPendingRemovals.isEmpty()
|| !mMoveAnimations.isEmpty()
|| !mRemoveAnimations.isEmpty()
|| !mAddAnimations.isEmpty()
|| !mChangeAnimations.isEmpty()
|| !mMovesList.isEmpty()
|| !mAdditionsList.isEmpty()
|| !mChangesList.isEmpty());
}
/**
* Check the state of currently pending and running animations. If there are none
* pending/running, call {@link #dispatchAnimationsFinished()} to notify any
* listeners.
*/
void dispatchFinishedWhenDone() {
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
@Override
public void endAnimations() {
int count = mPendingMoves.size();
for (int i = count - 1; i >= 0; i--) {
MoveInfo item = mPendingMoves.get(i);
View view = item.holder.itemView;
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item.holder);
mPendingMoves.remove(i);
}
count = mPendingRemovals.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = mPendingRemovals.get(i);
dispatchRemoveFinished(item);
mPendingRemovals.remove(i);
}
count = mPendingAdditions.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = mPendingAdditions.get(i);
item.itemView.setAlpha(1);
dispatchAddFinished(item);
mPendingAdditions.remove(i);
}
count = mPendingChanges.size();
for (int i = count - 1; i >= 0; i--) {
endChangeAnimationIfNecessary(mPendingChanges.get(i));
}
mPendingChanges.clear();
if (!isRunning()) {
return;
}
int listCount = mMovesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
count = moves.size();
for (int j = count - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
RecyclerView.ViewHolder item = moveInfo.holder;
View view = item.itemView;
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(moveInfo.holder);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(moves);
}
}
}
listCount = mAdditionsList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i);
count = additions.size();
for (int j = count - 1; j >= 0; j--) {
RecyclerView.ViewHolder item = additions.get(j);
View view = item.itemView;
view.setAlpha(1);
dispatchAddFinished(item);
additions.remove(j);
if (additions.isEmpty()) {
mAdditionsList.remove(additions);
}
}
}
listCount = mChangesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
count = changes.size();
for (int j = count - 1; j >= 0; j--) {
endChangeAnimationIfNecessary(changes.get(j));
if (changes.isEmpty()) {
mChangesList.remove(changes);
}
}
}
cancelAll(mRemoveAnimations);
cancelAll(mMoveAnimations);
cancelAll(mAddAnimations);
cancelAll(mChangeAnimations);
dispatchAnimationsFinished();
}
void cancelAll(List<RecyclerView.ViewHolder> viewHolders) {
for (int i = viewHolders.size() - 1; i >= 0; i--) {
viewHolders.get(i).itemView.animate().cancel();
}
}
/**
* {@inheritDoc}
* <p>
* If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
* When this is the case:
* <ul>
* <li>If you override {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)}, both
* ViewHolder arguments will be the same instance.
* </li>
* <li>
* If you are not overriding {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)},
* then DefaultItemAnimator will call {@link #animateMove(RecyclerView.ViewHolder, int, int, int, int)} and
* run a move animation instead.
* </li>
* </ul>
*/
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
}

View File

@@ -0,0 +1,181 @@
package com.mogo.och.shuttle.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mogo.och.shuttle.R
import com.mogo.och.shuttle.bean.BusQueryLinesResponse
import com.mogo.och.shuttle.ui.adapter.SwitchLineAdapter.SwitchLineViewHolder
import kotlin.text.StringBuilder
/**
* 路线列表adapter
*/
class SwitchLineAdapter(
private val mContext: Context,
private val mData: List<BusQueryLinesResponse.Result>
) : RecyclerView.Adapter<SwitchLineViewHolder>() {
companion object{
const val TAG = "SwitchLineAdapter"
}
// RecyclerView设置点击事件
private var mItemClickListener: LineItemClickListener? = null
var checkLineId:Int = -1
var checkTaskId:Int = -1
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): SwitchLineViewHolder {
val view = LayoutInflater.from(mContext).inflate(
R.layout.shuttle_switch_line_list_item, parent, false
)
return SwitchLineViewHolder(view)
}
override fun onBindViewHolder(holder: SwitchLineViewHolder, position: Int) {
val currentPosition = holder.bindingAdapterPosition
val line = mData[currentPosition]
if(line.name!=null&&line.name.length>10){
line.name = line.name.substring(0,10)+""
}
holder.lineName.text = line.name
val sb = StringBuilder()
if (line.endSiteName!=null&&line.endSiteName.length>10) {
sb.append(line.endSiteName.substring(0,5))
sb.append("")
sb.append(line.endSiteName.substring(line.endSiteName.length-5,line.endSiteName.length))
}else{
sb.append(line.endSiteName)
}
val string = mContext.getString(R.string.bus_line_goto_end, sb.toString())
holder.lineEndName.text = string
holder.rvLineTask.layoutManager = GridLayoutManager(mContext, 3)
val switchLineTaskAdapter = SwitchLineTaskAdapter(
mContext,
checkTaskId,
line.taskList,
object : SwitchLineTaskAdapter.TaskItemClickListener {
override fun onItemClick(position: Int,isCheck:Boolean) {
try {
if(isCheck) {
checkLineId = line.lineId
checkTaskId = line.taskList[position].id
}else{
checkLineId=-1
checkTaskId=-1
}
}catch (e:Exception){
e.printStackTrace()
checkLineId=-1
checkTaskId=-1
}
}
})
holder.rvLineTask.adapter = switchLineTaskAdapter
holder.rvLineTask.isFocusableInTouchMode = false
holder.actvShowMore.visibility = View.VISIBLE
if(line.open){
if(line.taskList==null||line.taskList.isEmpty()){
holder.actvShowMore.text = mContext.getString(R.string.bus_switch_line_no_task)
holder.actvShowMore.setTextColor(ContextCompat.getColor(mContext,R.color.bus_color_4dffffff))
holder.vLineTask.visibility = View.GONE
holder.rvLineTask.visibility = View.GONE
holder.selectIv.visibility = View.INVISIBLE
holder.itemView.setBackgroundResource(R.drawable.bus_shape_select_line_item_bg_normal)
}else {
holder.actvShowMore.text = mContext.getString(R.string.bus_switch_line_select_task)
holder.actvShowMore.setTextColor(ContextCompat.getColor(mContext,android.R.color.white))
holder.vLineTask.visibility = View.VISIBLE
holder.rvLineTask.visibility = View.VISIBLE
holder.selectIv.visibility = View.VISIBLE
holder.itemView.setBackgroundResource(R.drawable.bus_shape_select_line_item_bg_selected)
holder.selectIv.apply {
pivotX = 9.5f
pivotY = 17f
rotation = 90f
}
}
}else{
if(line.haveTask){
holder.actvShowMore.text = mContext.getString(R.string.bus_switch_line_no_task)
holder.actvShowMore.setTextColor(ContextCompat.getColor(mContext,R.color.bus_color_4dffffff))
holder.vLineTask.visibility = View.GONE
holder.rvLineTask.visibility = View.GONE
holder.selectIv.visibility = View.INVISIBLE
holder.itemView.setBackgroundResource(R.drawable.bus_shape_select_line_item_bg_normal)
}else {
holder.actvShowMore.text = mContext.getString(R.string.bus_switch_line_select_task)
holder.actvShowMore.setTextColor(ContextCompat.getColor(mContext,android.R.color.white))
holder.vLineTask.visibility = View.GONE
holder.rvLineTask.visibility = View.GONE
holder.selectIv.visibility = View.VISIBLE
holder.itemView.setBackgroundResource(R.drawable.bus_shape_select_line_item_bg_normal)
holder.selectIv.apply {
pivotX = 9.5f
pivotY = 17f
rotation = 0f
}
}
}
//设置item点击事件
holder.itemView.setOnClickListener {
if(holder.actvShowMore.text==mContext.getString(R.string.bus_switch_line_no_task)){
return@setOnClickListener
}
mData.forEachIndexed { index, result ->
if(result.open){
result.open = false;
notifyItemChanged(index)
if(result.taskList!=null) {
result.taskList.clear()
}
if(index==currentPosition){// 点击当前已经打开的item 去关闭定时网络请求
mItemClickListener?.onItemClick(currentPosition,true)
return@setOnClickListener
}
}
}
mItemClickListener?.onItemClick(currentPosition,false)
line.open = holder.rvLineTask.visibility == View.GONE
}
}
override fun getItemCount(): Int {
return mData.size
}
fun setOnLineItemClickListener(itemClickListener: LineItemClickListener?) {
mItemClickListener = itemClickListener
}
class SwitchLineViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val selectIv: ImageView
val lineName: AppCompatTextView//线路名称
val lineEndName: AppCompatTextView //终点
val actvShowMore: AppCompatTextView //选择时间
val rvLineTask: RecyclerView// 排班时间
val vLineTask: View// 白色分割线
init {
selectIv = itemView.findViewById(R.id.switch_line_item_select_iv)
lineName = itemView.findViewById(R.id.switch_line_name)
lineEndName = itemView.findViewById(R.id.switch_line_end_station)
rvLineTask = itemView.findViewById(R.id.rv_line_task_list)
vLineTask = itemView.findViewById(R.id.v_line_task)
actvShowMore = itemView.findViewById(R.id.actv_show_more)
}
}
interface LineItemClickListener {
fun onItemClick(position: Int,close:Boolean)
}
}

View File

@@ -0,0 +1,76 @@
package com.mogo.och.shuttle.ui.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.util.TimeUtils
import com.mogo.och.shuttle.R
import com.mogo.och.shuttle.bean.BusQueryLineTaskResponse
import com.mogo.och.shuttle.ui.adapter.SwitchLineTaskAdapter.SwitchLineTaskViewHolder
/**
* 路线列表adapter
*/
class SwitchLineTaskAdapter(
private val mContext: Context,
private var checkTaskId:Int,
private val mData: List<BusQueryLineTaskResponse.Result>?,
private val mTaskItemClickListener: TaskItemClickListener?
) : RecyclerView.Adapter<SwitchLineTaskViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SwitchLineTaskViewHolder {
val view = LayoutInflater.from(mContext).inflate(
R.layout.shuttle_switch_line_list_task_item, parent, false
)
return SwitchLineTaskViewHolder(view)
}
override fun onBindViewHolder(holder: SwitchLineTaskViewHolder, position: Int) {
val currentPosition = holder.bindingAdapterPosition
val task = mData!![currentPosition]
val taskStartTime = TimeUtils.millis2String(task.taskStartTime, "HH:mm")
holder.lineTask.text = taskStartTime
if(checkTaskId==task.id){
holder.lineTask.setBackgroundResource(R.drawable.bus_shape_select_line_item_time_bg_selected)
}else{
holder.lineTask.setBackgroundResource(R.drawable.bus_shape_select_line_item_time_bg)
}
holder.lineTask.setOnClickListener {
if(checkTaskId==task.id){
checkTaskId = -1
mTaskItemClickListener?.onItemClick(currentPosition,false)
}else {
resetOther()
checkTaskId = task.id
mTaskItemClickListener?.onItemClick(currentPosition,true)
}
notifyItemChanged(currentPosition)
}
}
private fun resetOther() {
mData?.forEachIndexed { index, result ->
if(result.id==checkTaskId){
checkTaskId = -1
notifyItemChanged(index)
}
}
}
override fun getItemCount(): Int {
return mData?.size ?: 0
}
class SwitchLineTaskViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val lineTask: TextView // 时间
init {
lineTask = itemView.findViewById(R.id.actv_line_task)
}
}
interface TaskItemClickListener {
fun onItemClick(position: Int,isCheck:Boolean)
}
}

View File

@@ -0,0 +1,55 @@
package com.mogo.och.shuttle.ui.writeoff
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import com.mogo.och.shuttle.R
import kotlinx.android.synthetic.main.shuttle_wirte_off_view.view.tv_write_off_count
class WriteOffView : ConstraintLayout, WriteOffViewModel.IwriteOffViewCallback {
private val TAG = "ItineraryView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.shuttle_wirte_off_view, this, true)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val viewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(WriteOffViewModel::class.java)
}
viewModel?.setWriteOffCallback(this)
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun setWriteOffCount(showText: String) {
tv_write_off_count.text = showText
}
}

View File

@@ -0,0 +1,70 @@
package com.mogo.och.shuttle.ui.writeoff
import androidx.lifecycle.ViewModel
import com.mogo.commons.AbsMogoApplication
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.och.shuttle.R
import com.mogo.och.shuttle.model.TicketModel
import com.mogo.och.common.module.utils.RxUtils
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
class WriteOffViewModel : ViewModel() {
private val TAG = WriteOffViewModel::class.java.simpleName
private var viewCallback: IwriteOffViewCallback? = null
init {
}
private var disposable: Disposable? = null
private val observer = object : Observer<String> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onError(e: Throwable) {
}
override fun onComplete() {
}
override fun onNext(countInfo: String) {
viewCallback?.setWriteOffCount(countInfo)
}
}
fun setWriteOffCallback(viewCallback: IwriteOffViewCallback) {
this.viewCallback = viewCallback
TicketModel
.getWriteOffCountObservable()
.flatMap { t ->
val showText =
AbsMogoApplication.getApp().getString(R.string.shuttle_write_off_count, t)
CallerLogger.d(SceneConstant.M_BUS + TAG, "显示文案:${showText}")
Observable.just(showText)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer)
}
override fun onCleared() {
super.onCleared()
this.viewCallback = null
RxUtils.disposeSubscribe(disposable)
}
interface IwriteOffViewCallback {
fun setWriteOffCount(count:String)
}
}

View File

@@ -0,0 +1,56 @@
package com.mogo.och.shuttle.util;
import androidx.annotation.NonNull;
import com.mogo.och.common.module.manager.autopilot.autopilot.OchAutopilotAnalytics;
/**
* OCH Bus埋点工具
* <p>
* Created on 2022/3/24
*/
public class BusAnalyticsManager extends OchAutopilotAnalytics {
// 埋点key开启自动驾驶前已识别的异常会导致无法开启自驾
private static final String EVENT_KEY_AP_UNABLE_START_REASON = "event_key_och_bus_ap_unable_start_reason";
// 埋点key接管后点击'自动驾驶'按钮启动
private static final String EVENT_KEY_RESTART_AUTOPILOT = "event_key_och_bus_restart_autopilot";
// 埋点key开始服务开启自动驾驶成功/失败)
private static final String EVENT_KEY_START_SERVICE = "event_key_och_bus_start_service";
// 埋点key点击启动自驾
private static final String EVENT_KEY_CLICK_START_AUTOPILOT = "event_key_och_shuttle_click_start_autopilot";
private static final class SingletonHolder {
private static final BusAnalyticsManager INSTANCE = new BusAnalyticsManager();
}
public static BusAnalyticsManager getInstance() {
return BusAnalyticsManager.SingletonHolder.INSTANCE;
}
@NonNull
@Override
public String getEventKeyStartService() {
return EVENT_KEY_START_SERVICE;
}
@NonNull
@Override
public String getEventKeyRestartService() {
return EVENT_KEY_RESTART_AUTOPILOT;
}
@NonNull
@Override
public String getEventKeyApUnableStartReason() {
return EVENT_KEY_AP_UNABLE_START_REASON;
}
@NonNull
@Override
public String getEventKeyClickStartAutopilot() {
return EVENT_KEY_CLICK_START_AUTOPILOT;
}
}

View File

@@ -0,0 +1,36 @@
package com.mogo.och.shuttle.util
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
/**
* @author: wangmingjun
* @date: 2022/10/24
*/
object BusSendTripInfoManager{
const val START_TRIP = 1
const val END_TRIP = 2
const val LEAVE_STATION = 3
const val ARRIVE_STATION = 4
/**
* 行程信息
* @param type 事件类型, 1:行程开始, 2:行程结束, 3:出站, 4:进站, 5:城市占道施工预警
* @param lineName 路线名, for type 1, 2
* @param departureStopName 出站站点名, for type 3, 4
* @param arrivalStopName 下一站到达站点名, for type 3, 4
* @param isLastStop 是否终点站(下一站或者要到达站)
* @return
*/
fun sendBusTripInfo(type: Int, lineName: String,
departureStopName: String,
arrivalStopName: String,
isLastStop: Boolean) {
d(SceneConstant.M_BUS + "BusSendTripInfoManager", "type: "+ type
+", lineName: "+ lineName +", departureStopName: "+ departureStopName
+ ", arrivalStopName: "+arrivalStopName+", isLastStop: "+isLastStop)
CallerAutoPilotControlManager.sendTripInfo(type,lineName,departureStopName, arrivalStopName, isLastStop)
}
}

View File

@@ -0,0 +1,204 @@
package com.mogo.och.shuttle.util;
import androidx.annotation.Nullable;
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.eagle.core.utilcode.util.GsonUtils;
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager;
import com.mogo.och.data.bean.BusRoutesResult;
import com.mogo.och.shuttle.constant.BusConst;
import com.mogo.och.shuttle.model.OrderModel;
import com.mogo.och.common.module.biz.login.LoginStatusManager;
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;
import mogo_msg.MogoReportMsg;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
/**
* Bus轨迹管理给MEC下发用于轨迹下载的信息
* Created on 2022/6/23
*/
public class BusTrajectoryManager {
private static final String TAG = BusTrajectoryManager.class.getSimpleName();
private static final class SingletonHolder {
private static final BusTrajectoryManager INSTANCE = new BusTrajectoryManager();
}
public static BusTrajectoryManager getInstance() {
return BusTrajectoryManager.SingletonHolder.INSTANCE;
}
private AutopilotControlParameters.AutoPilotLine mAutoPilotLine = null;
private Disposable mSendReqDisposable = null;
public BusTrajectoryManager() {
mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine(-1, "",
"", "", "", "", 0, "",
"", "", "", "", 0);
}
/**
* 同步Bus路线信息
*/
public void syncTrajectoryInfo() {
BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult();
if (LoginStatusManager.isLogin() && routesResult != null
&& OrderModel.getInstance().getCurrentStationIndex() == 0
&& !OrderModel.getInstance().isGoingToNextStation()) {
CallerLogger.d(M_BUS + TAG, "syncTrajectoryInfo() start.");
startTrajReqLoop();
} else {
// 无路线信息or当前未在始发站
CallerLogger.d(M_BUS + TAG, "syncTrajectoryInfo() stop.");
stopTrajReqLoop();
}
}
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo,long lineId) {
onAutopilotGuardian(guardianInfo);
}
/**
* 接口MEC反馈的常规信息MAP v2.5.0新增轨迹相关信息)
* @param guardianInfo
*/
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
if (guardianInfo == null || !guardianInfo.hasCode()) return;
if ("ISYS_INIT_TRAJECTORY_START".equals(guardianInfo.getCode())) {
// 1. 轨迹管理_轨迹开始下载本地已有对应轨迹也触发
CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹开始下载");
OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹开始下载", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
// ToastUtils.showShort("轨迹开始下载");
stopTrajReqLoop();
} else if ("ISYS_INIT_TRAJECTORY_SUCCESS".equals(guardianInfo.getCode())) {
// 2. 轨迹管理_轨迹下载成功本地已有对应轨迹也触发
CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹下载成功");
OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载成功", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
// ToastUtils.showShort("轨迹下载成功");
stopTrajReqLoop();
} else if ("ISYS_INIT_TRAJECTORY_FAILURE".equals(guardianInfo.getCode())) {
// 3. 轨迹管理_轨迹下载失败本地无对应轨迹
CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() " +
"轨迹下载失败,本地无对应轨迹");
OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载失败,本地无对应轨迹", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
// ToastUtils.showShort("轨迹下载失败,本地无对应轨迹");
} else if ("ISYS_INIT_TRAJECTORY_WARNING".equals(guardianInfo.getCode())) {
// 4. 轨迹管理_轨迹下载失败本地有对应轨迹认为成功
CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() " +
"轨迹下载失败,本地有对应轨迹,认为成功");
OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载失败,本地有对应轨迹,认为成功", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
// ToastUtils.showShort("轨迹下载失败,本地有对应轨迹,认为成功");
} else if ("ISYS_INIT_TRAJECTORY_TIMEOUT".equals(guardianInfo.getCode())) {
// 5. 轨迹管理_轨迹下载超时
CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() 轨迹下载超时");
OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 轨迹下载超时", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
// ToastUtils.showShort("轨迹下载超时");
} else if ("ISSM_FUNC_AUTO_PILOT_READY".equals(guardianInfo.getCode())) {
// 收到ssm的自动驾驶变为ready再次下发轨迹下载.解决域控重启或者102域控启动太早107节点初始化未完成导致的轨迹未进行下载。
CallerLogger.d(M_BUS + TAG, "onAutopilotGuardian() ssm ready再次发起下载");
OchChainLogManager.writeChainLog("轨迹监控","onAutopilotGuardian() 再次发起下载", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
syncTrajectoryInfo();
}
}
private void setupAutoPilotLine() {
BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult();
if (routesResult == null) {
CallerLogger.e(M_BUS + TAG,
"setupAutoPilotLine(): routesResult is null.");
return;
} else {
if (mAutoPilotLine == null) {
mAutoPilotLine = new AutopilotControlParameters.AutoPilotLine(
routesResult.getLineId(), routesResult.getName(),
routesResult.csvFileUrl, routesResult.csvFileMd5,
routesResult.txtFileUrl, routesResult.txtFileMd5,
routesResult.contrailSaveTime, routesResult.carModel,
routesResult.csvFileUrlDPQP, routesResult.csvFileMd5DPQP,
routesResult.txtFileUrlDPQP, routesResult.txtFileMd5DPQP,
routesResult.contrailSaveTimeDPQP);
} else {
mAutoPilotLine.setLineId(routesResult.getLineId());
mAutoPilotLine.setLineName(routesResult.getName());
mAutoPilotLine.setTrajUrl(routesResult.csvFileUrl);
mAutoPilotLine.setTrajMd5(routesResult.csvFileMd5);
mAutoPilotLine.setStopUrl(routesResult.txtFileUrl);
mAutoPilotLine.setStopMd5(routesResult.txtFileMd5);
mAutoPilotLine.setTimestamp(routesResult.contrailSaveTime);
mAutoPilotLine.setVehicleModel(routesResult.carModel);
mAutoPilotLine.setTrajUrl_dpqp(routesResult.csvFileUrlDPQP);
mAutoPilotLine.setTrajMd5_dpqp(routesResult.csvFileMd5DPQP);
mAutoPilotLine.setStopUrl_dpqp(routesResult.txtFileUrlDPQP);
mAutoPilotLine.setStopMd5_dpqp(routesResult.txtFileMd5DPQP);
mAutoPilotLine.setTimestamp_dpqp(routesResult.contrailSaveTimeDPQP);
}
}
}
private void clearAutoPilotLine() {
if (mAutoPilotLine == null) return;
mAutoPilotLine.setLineId(-1);
mAutoPilotLine.setLineName("");
mAutoPilotLine.setTrajUrl("");
mAutoPilotLine.setTrajMd5("");
mAutoPilotLine.setStopUrl("");
mAutoPilotLine.setStopMd5("");
mAutoPilotLine.setTimestamp(0);
mAutoPilotLine.setVehicleModel("");
mAutoPilotLine.setTrajUrl_dpqp("");
mAutoPilotLine.setTrajMd5_dpqp("");
mAutoPilotLine.setStopUrl_dpqp("");
mAutoPilotLine.setStopMd5_dpqp("");
mAutoPilotLine.setTimestamp_dpqp(0);
}
private void startTrajReqLoop() {
if (mSendReqDisposable != null && !mSendReqDisposable.isDisposed()) {
return;
}
CallerLogger.d(M_BUS + TAG, "startTrajReqLoop()");
setupAutoPilotLine();
mSendReqDisposable = Observable.interval(BusConst.LOOP_DELAY,
BusConst.LOOP_PERIOD_10S, TimeUnit.MILLISECONDS)
.map((aLong -> aLong + 1))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
if (aLong > BusConst.LOOP_SEND_TRAJ_TIMES) {
stopTrajReqLoop();
return;
}
CallerLogger.d(M_BUS + TAG, "loop sendTrajectoryReq: " + aLong);
sendTrajectoryReq();
});
}
public void stopTrajReqLoop() {
if (mSendReqDisposable != null) {
CallerLogger.d(M_BUS + TAG, "stopTrajReqLoop()");
mSendReqDisposable.dispose();
mSendReqDisposable = null;
clearAutoPilotLine();
}
}
private void sendTrajectoryReq() {
if (mAutoPilotLine == null) {
CallerLogger.e(M_BUS + TAG, "sendTrajectoryReq(): mAutoPilotLine is null!!!");
return;
}
OchChainLogManager.writeChainLog("轨迹监控","sendTrajectoryReq() 下发轨迹 轨迹id"+mAutoPilotLine.getLineId(), true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY);
CallerAutoPilotControlManager.INSTANCE.sendTrajectoryDownloadReq(mAutoPilotLine);
CallerLogger.d(M_BUS + TAG, "sendTrajectoryReq(): "
+ GsonUtils.toJson(mAutoPilotLine));
}
}

View File

@@ -0,0 +1,93 @@
package com.mogo.och.shuttle.util
import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.och.shuttle.R
import com.mogo.och.common.module.voice.VoiceNotice
import com.mogo.tts.base.LangTtsEntity
import com.mogo.tts.base.LanguageType
import java.util.ArrayList
object ShuttleVoiceManager {
fun arrivedStationBus(siteNameCN: String?, siteNameKR: String?) {
val context = AbsMogoApplication.getApp()
val list: MutableList<LangTtsEntity> = ArrayList()
siteNameCN?.let {
val chineseTTS = LangTtsEntity(
context.getString(R.string.bus_arrived_station_tip, it),
LanguageType.CHINESE
)
val engTTS = LangTtsEntity(
context.getString(R.string.bus_arrived_station_english_tip, it),
LanguageType.ENGLISH
)
val koreanTTS = LangTtsEntity(
context.getString(R.string.bus_arrived_station_korean_tip, siteNameKR?:it),
LanguageType.KOREAN
)
list.add(chineseTTS)
list.add(engTTS)
list.add(koreanTTS)
}
VoiceNotice.showNotice(list, AIAssist.LEVEL1,null)
}
fun leaveStationBus(siteNameCN: String?, siteNameKR: String?) {
val list: MutableList<LangTtsEntity> = ArrayList()
val context = AbsMogoApplication.getApp()
siteNameCN?.let {
val chineseTTS = LangTtsEntity(
context.getString(R.string.bus_leave_station_tip, it),
LanguageType.CHINESE
)
val engTTS = LangTtsEntity(
context.getString(R.string.bus_leave_station_english_tip, it),
LanguageType.ENGLISH
)
list.add(chineseTTS)
list.add(engTTS)
val koreanTTS = LangTtsEntity(
context.getString(R.string.bus_leave_station_korean_tip, siteNameKR ?: it),
LanguageType.KOREAN
)
list.add(koreanTTS)
}
VoiceNotice.showNotice(list, AIAssist.LEVEL1,null)
}
fun endOrderBus() {
val context = AbsMogoApplication.getApp()
val list: MutableList<LangTtsEntity> = ArrayList()
val chineseTTS = LangTtsEntity(context.getString(R.string.bus_end_task_tip), LanguageType.CHINESE)
val engTTS = LangTtsEntity(context.getString(R.string.bus_end_task_english_tip), LanguageType.ENGLISH)
val koreanTTS = LangTtsEntity(context.getString(R.string.bus_end_task_korean_tip), LanguageType.KOREAN)
list.add(chineseTTS)
list.add(engTTS)
list.add(koreanTTS)
VoiceNotice.showNotice(list, AIAssist.LEVEL0,null)
}
fun writeOffCount(successNum:Int){
if(successNum<=1){
VoiceNotice.showNotice("核验通过", AIAssist.LEVEL3);
}else{
VoiceNotice.showNotice("$successNum 人核验通过", AIAssist.LEVEL3)
}
}
// 距离发车还有1分钟
fun showLeafTime(tips: String) {
//语音提示
VoiceNotice.showNotice(tips)
}
fun writeOffFaile(reaseon:String) {
VoiceNotice.showNotice("验票失败,${reaseon}", AIAssist.LEVEL3)
}
}

View File

@@ -0,0 +1,63 @@
package com.mogo.och.shuttle.view
import android.content.Context
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.function.view.MapBizView
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.map.uicontroller.IMogoMapUIController
import com.mogo.och.shuttle.R
/**
* 魔戒蓝牙控件
* 放置于StatusBar右侧位置
*/
class BizMapView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private lateinit var mapBizView: MapBizView
init {
if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
LayoutInflater.from(context).inflate(R.layout.shuttle_m2_bizmap_map, this, true)
}else if(AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)){
LayoutInflater.from(context).inflate(R.layout.shuttle_jl_bizmap_map, this, true)
}else{
LayoutInflater.from(context).inflate(R.layout.shuttle_jl_bizmap_map, this, true)
}
mapBizView = findViewById(R.id.bizMapView)
}
fun getUI(): IMogoMapUIController? {
return mapBizView.getUI()
}
fun onCreate(bundle: Bundle?) {
mapBizView.onCreate(bundle)
}
fun onResume() {
mapBizView.onResume()
}
fun onSaveInstanceState(outState: Bundle){
mapBizView.onSaveInstanceState(outState)
}
fun onLowMemory() {
mapBizView.onLowMemory()
}
fun onPause() {
mapBizView.onPause()
}
fun onDestroy() {
mapBizView.onDestroy()
}
}

View File

@@ -0,0 +1,300 @@
package com.mogo.och.shuttle.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.commons.AbsMogoApplication;
import com.mogo.eagle.core.utilcode.util.ConvertUtils;
import com.mogo.eagle.core.utilcode.util.ThreadUtils;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.shuttle.R;
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager;
import me.jessyan.autosize.AutoSizeConfig;
import me.jessyan.autosize.utils.AutoSizeUtils;
/**
* 滑块滑动面板
*
* @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 = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),15);
private static int BLOCK_START_Y = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),15);
private static int NORMAL_TEXT_MARGIN_LEFT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),40);
private static int NORMAL_TEXT_MARGIN_RIGHT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),60);
private static int SHORT_TEXT_MARGIN_LEFT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),60);;
private static int SHORT_TEXT_MARGIN_RIGHT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),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 final 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() {
bgRectF = new RectF(0, 0, 0, 0);
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);
decodeImage();
}
private void decodeImage(){
ThreadUtils.getCpuPool().execute(() -> {
int size = AutoSizeUtils.dp2px(getContext(), 120);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inDensity = (int) AutoSizeConfig.getInstance().getInitDensity();
bmBlock = BitmapFactory.decodeResource(getResources(), R.drawable.bus_base_slide_block,opts);
bmBlock = Bitmap.createScaledBitmap(bmBlock, size, size, true);
blockWidth = bmBlock.getWidth();
UiThreadHandler.post(this::requestLayout,UiThreadHandler.MODE.QUEUE);
});
}
@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(bmBlock!=null) {
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);
if (bgRectF != null){
bgRectF.left = 0;
bgRectF.top = 0;
bgRectF.right = w;
bgRectF.bottom = 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 blockBackanimator = ObjectAnimator.ofInt(this, "blockOffset", blockOffset, 0);
blockBackanimator.setInterpolator(new DecelerateInterpolator());
blockBackanimator.setDuration(1000 * blockOffset / getWidth());
blockBackanimator.start();
lastX = 0;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 画背景
canvas.drawRoundRect(bgRectF, (float) getHeight() / 2.0f, (float) getHeight() / 2.0f, bgPaint);
// 画文字
gradientMatrix.setTranslate(matrixTranslate, 0);
textGradient.setLocalMatrix(gradientMatrix);
canvas.save();
canvas.drawText(blockText, (float) (blockWidth + BLOCK_START_X + textMarginLeft), (float) textOffset, textPaint);
canvas.restore();
if (bmBlock != null) {
if(bmBlock.getByteCount()>=5*1024*1024){
OchChainLogManager.writeChainLog("崩溃兜底策略",
"图片大小监听"+ ConvertUtils.byte2FitMemorySize(bmBlock.getByteCount()),true,OchChainLogManager.EVENT_KEY_INFE_ERROR);
bmBlock.recycle();
bmBlock = null;
blockWidth = 0;
decodeImage();
}else {
// 画滑块
canvas.drawBitmap(bmBlock, (float) (BLOCK_START_X + blockOffset), (float) BLOCK_START_Y, blockPaint);
}
}
}
public interface OnSlidePanelMoveToEndListener {
/**
* 滑块滑到了末尾
*/
void moveToEnd();
}
}

View File

@@ -0,0 +1,64 @@
package com.mogo.och.shuttle.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);
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/bus_autopilot_text_color_normal"/>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon_ai_select" android:state_focused="true" android:state_pressed="true" />
<item android:drawable="@drawable/icon_ai_select" android:state_focused="false" android:state_pressed="true" />
<item android:drawable="@drawable/icon_ai_select" android:state_selected="true" />
<item android:drawable="@drawable/icon_ai_select" android:state_focused="true" />
<item android:drawable="@drawable/icon_ai_normal" />
</selector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon_bad_case_select" android:state_focused="true" android:state_pressed="true" />
<item android:drawable="@drawable/icon_bad_case_select" android:state_focused="false" android:state_pressed="true" />
<item android:drawable="@drawable/icon_bad_case_select" android:state_selected="true" />
<item android:drawable="@drawable/icon_bad_case_select" android:state_focused="true" />
<item android:drawable="@drawable/icon_bad_case_normal" />
</selector>

Some files were not shown because too many files have changed in this diff Show More