新增上报求助功能
This commit is contained in:
@@ -28,6 +28,10 @@ public class ShareControl implements IShareControl {
|
||||
(IMogoServiceApis) ARouter.getInstance().build(MogoServicePaths.PATH_SERVICE_APIS).navigation(context);
|
||||
}
|
||||
|
||||
public IMogoServiceApis getMogoServiceApis(){
|
||||
return mogoServiceApis;
|
||||
}
|
||||
|
||||
public static ShareControl getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
synchronized (ShareControl.class) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.mogo.module.share
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.mogo.module.share.constant.ShareConstants
|
||||
|
||||
/**
|
||||
* 用于接收唤醒词指令
|
||||
*/
|
||||
class ShareVoiceCmdReceiver:BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
// todo 接收唤醒词指令
|
||||
|
||||
// todo 开启服务,准备上报求助
|
||||
context?.let {
|
||||
val seekHelp = Intent(it, VoiceCmdService::class.java)
|
||||
seekHelp.putExtra(ShareConstants.VOICE_CMD_SERVICE_EVENT_KEY, ShareConstants.VOICE_CMD_SERVICE_SEEK_HELP)
|
||||
it.startService(seekHelp)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.mogo.module.share
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import com.mogo.module.share.constant.ShareConstants
|
||||
import com.mogo.module.share.manager.ISeekHelpListener
|
||||
import com.mogo.module.share.manager.SeekHelpManager
|
||||
import com.mogo.utils.logger.Logger
|
||||
|
||||
/**
|
||||
* 用来处理唤醒词
|
||||
*
|
||||
* @author tongchenfei
|
||||
*/
|
||||
class VoiceCmdService:Service() {
|
||||
companion object{
|
||||
private const val TAG = "VoiceCmdService"
|
||||
}
|
||||
|
||||
private val seekListener = object : ISeekHelpListener{
|
||||
override fun onSeekHelpSuccess() {
|
||||
// 上报完成,关掉自己
|
||||
Logger.d(TAG,"上报完成,成功")
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
override fun onSeekHelpFail() {
|
||||
// 上报完成,关掉自己
|
||||
Logger.d(TAG,"上报完成,失败")
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
intent?.let {
|
||||
if (intent.getIntExtra(ShareConstants.VOICE_CMD_SERVICE_EVENT_KEY,0) == ShareConstants.VOICE_CMD_SERVICE_SEEK_HELP) {
|
||||
// 收到语音指令,准备上报求助
|
||||
Logger.i(TAG, "收到语音指令,准备上报求助")
|
||||
SeekHelpManager.seekHelp(this,seekListener)
|
||||
}
|
||||
}
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Logger.d(TAG, "onDestroy")
|
||||
SeekHelpManager.removeSeekHelpListener(seekListener)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.mogo.module.share.bean
|
||||
|
||||
/**
|
||||
* 求助记录,recordTime建议使用SystemClock.elapsedRealtime记录,因为此时间主要是为了做时间差,而不是精确时间
|
||||
*/
|
||||
data class SeekRecord(val recordTime: Long)
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.mogo.module.share.constant
|
||||
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
|
||||
class HttpConstant {
|
||||
|
||||
companion object {
|
||||
const val HOST_DEV = "http://dzt-test.zhidaohulian.com"
|
||||
const val HOST_TEST = "http://dzt-test.zhidaohulian.com"
|
||||
const val HOST_PRODUCT = "https://dzt.zhidaohulian.com"
|
||||
|
||||
fun getNetHost(): String {
|
||||
return when (DebugConfig.getNetMode()) {
|
||||
DebugConfig.NET_MODE_DEV -> HOST_DEV
|
||||
DebugConfig.NET_MODE_QA -> HOST_TEST
|
||||
else -> HOST_PRODUCT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,4 +15,7 @@ public class ShareConstants {
|
||||
public static final String LAUNCHER_SHARE_CLICK = "Launcher_Share_Click";
|
||||
//
|
||||
public static final String CARNET_USER_UPLOAD = "CarNet_user_upload";
|
||||
|
||||
public static final String VOICE_CMD_SERVICE_EVENT_KEY = "type";
|
||||
public static final int VOICE_CMD_SERVICE_SEEK_HELP = 1;
|
||||
}
|
||||
|
||||
@@ -9,15 +9,16 @@ import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.mogo.module.share.R;
|
||||
import com.mogo.module.share.ShareControl;
|
||||
import com.mogo.module.share.constant.ShareConstants;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
import com.mogo.module.share.manager.ISeekHelpListener;
|
||||
import com.mogo.module.share.manager.SeekHelpManager;
|
||||
import com.mogo.service.analytics.IMogoAnalytics;
|
||||
import com.mogo.utils.WindowUtils;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
@@ -38,77 +39,99 @@ public class LaucherShareDialog implements View.OnClickListener {
|
||||
|
||||
private boolean isShown = false;
|
||||
|
||||
private TextView txtOk;
|
||||
private RelativeLayout mBlockLayout;
|
||||
private RelativeLayout mOilPriceLayout;
|
||||
private RelativeLayout mTrafficCheckLayout;
|
||||
private RelativeLayout mRoadClosureLayout;
|
||||
private TextView tvBlock;
|
||||
private TextView tvTrafficCheck;
|
||||
private TextView tvClosure;
|
||||
private TextView tvNeedHelp;
|
||||
private Context mContext;
|
||||
private IMogoAnalytics mAnalytics;
|
||||
|
||||
|
||||
private WindowManager windowManager;
|
||||
private WindowManager.LayoutParams layoutParams;
|
||||
|
||||
public LaucherShareDialog(@NonNull Context context) {
|
||||
this.mContext = context;
|
||||
mAnalytics = (IMogoAnalytics) ARouter.getInstance().build(MogoServicePaths.PATH_UTILS_ANALYTICS).navigation(mContext);
|
||||
mAnalytics = ShareControl.getInstance(context).getMogoServiceApis().getAnalyticsApi();
|
||||
}
|
||||
|
||||
private View body;
|
||||
private void initView() {
|
||||
Logger.d(TAG, "test-------3");
|
||||
body = LayoutInflater.from(mContext).inflate(R.layout.launcher_dialog_share, null);
|
||||
body = LayoutInflater.from(mContext).inflate(R.layout.launcher_dialog_share_2, null);
|
||||
body.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
txtOk = body.findViewById(R.id.btn_share_title);
|
||||
mBlockLayout = body.findViewById(R.id.btn_block_layout);
|
||||
mOilPriceLayout = body.findViewById(R.id.oil_price_layout);
|
||||
mTrafficCheckLayout = body.findViewById(R.id.traffic_check_layout);
|
||||
mRoadClosureLayout = body.findViewById(R.id.road_closure_layout);
|
||||
tvBlock = body.findViewById(R.id.tvBlock);
|
||||
tvTrafficCheck = body.findViewById(R.id.tvTrafficCheck);
|
||||
tvClosure = body.findViewById(R.id.tvClosure);
|
||||
tvNeedHelp = body.findViewById(R.id.tvNeedHelp);
|
||||
}
|
||||
|
||||
|
||||
private void initListener() {
|
||||
mBlockLayout.setOnClickListener(this);
|
||||
mOilPriceLayout.setOnClickListener(this);
|
||||
mTrafficCheckLayout.setOnClickListener(this);
|
||||
mRoadClosureLayout.setOnClickListener(this);
|
||||
|
||||
tvBlock.setOnClickListener(this);
|
||||
tvNeedHelp.setOnClickListener(this);
|
||||
tvTrafficCheck.setOnClickListener(this);
|
||||
tvClosure.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
int id = view.getId();
|
||||
Logger.d(TAG, "onClick: " + id);
|
||||
if (id == R.id.btn_block_layout) { //拥堵
|
||||
if (id == R.id.tvBlock) {
|
||||
//拥堵
|
||||
traceTanluData("1");
|
||||
sendShareReceiver("1");
|
||||
traceTypeData("1");
|
||||
dismiss();
|
||||
} else if (id == R.id.oil_price_layout) {
|
||||
// 分享油价,入口被屏蔽了
|
||||
traceData("1");
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse("freshthing://com.zhidao.fresh.things/shareOilPrice"));
|
||||
mContext.startActivity(intent);
|
||||
traceTypeData("2");
|
||||
dismiss();
|
||||
} else if (id == R.id.traffic_check_layout) { //交通检查
|
||||
} else if (id == R.id.tvTrafficCheck) {
|
||||
//交通检查
|
||||
traceData("1");
|
||||
sendShareReceiver("2");
|
||||
traceTypeData("3");
|
||||
dismiss();
|
||||
} else if (id == R.id.road_closure_layout) { //封路
|
||||
} else if (id == R.id.tvClosure) {
|
||||
//封路
|
||||
traceData("1");
|
||||
sendShareReceiver("3");
|
||||
traceTypeData("4");
|
||||
dismiss();
|
||||
} else if (id == R.id.tvNeedHelp) {
|
||||
// 故障求助
|
||||
SeekHelpManager.INSTANCE.seekHelp(mContext,seekListener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ISeekHelpListener seekListener = new ISeekHelpListener() {
|
||||
@Override
|
||||
public void onSeekHelpSuccess() {
|
||||
Logger.d(TAG,"上报求助完成,成功");
|
||||
SeekHelpManager.INSTANCE.removeSeekHelpListener(seekListener);
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekHelpFail() {
|
||||
Logger.d(TAG,"上报求助完成,失败");
|
||||
SeekHelpManager.INSTANCE.removeSeekHelpListener(seekListener);
|
||||
dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送广播 1拥堵,2交通检查,3封路
|
||||
*/
|
||||
@@ -156,20 +179,21 @@ public class LaucherShareDialog implements View.OnClickListener {
|
||||
Logger.d(TAG,"使用windowManager实现");
|
||||
if (!isShown) {
|
||||
windowManager = (WindowManager) mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
layoutParams = new WindowManager.LayoutParams();
|
||||
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
layoutParams.format = PixelFormat.TRANSLUCENT;
|
||||
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
layoutParams.gravity = Gravity.START | Gravity.TOP;
|
||||
// mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
// FLAG_LAYOUT_IN_SCREEN:将window放置在整个屏幕之内,无视其他的装饰(比如状态栏); FLAG_NOT_TOUCH_MODAL:不阻塞事件传递到后面的窗口
|
||||
layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
layoutParams.width = WindowUtils.getScreenWidth(mContext);
|
||||
layoutParams.height = WindowUtils.getScreenHeight(mContext);
|
||||
layoutParams.dimAmount = 0;//后面变暗区域透明...
|
||||
//后面变暗区域透明...
|
||||
layoutParams.dimAmount = 0;
|
||||
layoutParams.x = 0;
|
||||
layoutParams.y = 0;
|
||||
initView();
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.module.share.manager
|
||||
|
||||
/**
|
||||
* 寻求帮助结果监听
|
||||
*/
|
||||
interface ISeekHelpListener {
|
||||
/**
|
||||
* 寻求帮助成功
|
||||
*/
|
||||
fun onSeekHelpSuccess()
|
||||
|
||||
/**
|
||||
* 寻求帮助失败
|
||||
*/
|
||||
fun onSeekHelpFail()
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.mogo.module.share.manager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.SystemClock
|
||||
import android.widget.Toast
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.mogo.commons.data.BaseData
|
||||
import com.mogo.commons.network.SubscribeImpl
|
||||
import com.mogo.commons.voice.AIAssist
|
||||
import com.mogo.commons.voice.IMogoVoiceCmdCallBack
|
||||
import com.mogo.module.share.ShareControl
|
||||
import com.mogo.module.share.bean.SeekRecord
|
||||
import com.mogo.module.share.constant.HttpConstant
|
||||
import com.mogo.module.share.net.ShareApiService
|
||||
import com.mogo.service.IMogoServiceApis
|
||||
import com.mogo.service.MogoServicePaths
|
||||
import com.mogo.utils.logger.Logger
|
||||
import com.mogo.utils.network.RequestOptions
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
/**
|
||||
* 故障求助管理类,相关故障求助操作的具体实现类
|
||||
* @author tongchenfei
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object SeekHelpManager {
|
||||
const val TAG = "SeekHelpManager"
|
||||
/**
|
||||
* 发起求助记录的限制时间,也就是只关注这段时间内的求助记录
|
||||
*/
|
||||
private const val SEEK_RECORD_LIMIT_TIME = 10 * 60 * 1000
|
||||
/**
|
||||
* 限制时间内,发起求助记录的限制次数
|
||||
*/
|
||||
private const val SEEK_RECORD_LIMIT_AMOUNT = 2
|
||||
const val VOICE_WILL_SEEK_HELP = "将发布故障求助"
|
||||
|
||||
private var context:Context? = null
|
||||
private var aiAssist:AIAssist? = null
|
||||
|
||||
private val seekRecordList = mutableListOf<SeekRecord>()
|
||||
private val seekListenerList = mutableListOf<ISeekHelpListener>()
|
||||
private var isSeekHelp = false
|
||||
|
||||
private val voiceCallback = object : IMogoVoiceCmdCallBack {
|
||||
override fun onCmdSelected(cmd: String?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCmdAction(speakText: String?) {
|
||||
}
|
||||
|
||||
override fun onCmdCancel(speakText: String?) {
|
||||
}
|
||||
|
||||
override fun onSpeakEnd(speakText: String?) {
|
||||
speakText?.let {
|
||||
Logger.d(TAG, "onSpeakEnd: $it")
|
||||
if (it == VOICE_WILL_SEEK_HELP) {
|
||||
// 请求帮助语音播放完成,开始真正寻求帮助
|
||||
realSeekHelp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSpeakSelectTimeOut(speakText: String?) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 寻求帮助,是开始故障求助的入口
|
||||
* 由于当前需求仅需要提供这一个方法,所以context的初始化放到了此方法,后面如果有增加,需要把这部分提出去
|
||||
*/
|
||||
fun seekHelp(context: Context, seekHelpListener: ISeekHelpListener) {
|
||||
// context初始化
|
||||
if (this.context == null) {
|
||||
this.context = context
|
||||
aiAssist = AIAssist.getInstance(context)
|
||||
}
|
||||
Logger.d(TAG, "开始故障求助上报---${isSeekHelp}")
|
||||
seekListenerList.add(seekHelpListener)
|
||||
when {
|
||||
isSeekHelp -> {
|
||||
// 正在求助中,进行异常提示
|
||||
toast("已发布故障求助,请耐心等待")
|
||||
aiAssist?.speakTTSVoice("已发布故障求助,请耐心等待")
|
||||
}
|
||||
getSeekAmountByLimitTime() >= SEEK_RECORD_LIMIT_AMOUNT -> {
|
||||
// 超过限制时间内的限制次数,进行异常提示
|
||||
toast("已在求助状态,请勿连续发布哦")
|
||||
aiAssist?.speakTTSVoice("已在求助状态,请勿连续发布哦")
|
||||
}
|
||||
else -> {
|
||||
// 没有异常情况,开始故障求助
|
||||
aiAssist?.speakTTSVoice(VOICE_WILL_SEEK_HELP, voiceCallback)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun removeSeekHelpListener(seekHelpListener: ISeekHelpListener) {
|
||||
seekListenerList.remove(seekHelpListener)
|
||||
}
|
||||
|
||||
private fun toast(msg: String) {
|
||||
Toast.makeText(context, msg, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得限制时间 {@link SEEK_RECORD_LIMIT_TIME} 内的请求次数,现在的请求记录是保存在内存中的,如果遇到Launcher的Crash,此记录会被重置
|
||||
* 此方法就是把seekRecordList里面超过限制时间的选项去掉,然后剩下的就是时限内的请求次数
|
||||
*
|
||||
* @return 规定时间内的请求次数
|
||||
*/
|
||||
private fun getSeekAmountByLimitTime(): Int {
|
||||
val current = SystemClock.elapsedRealtime()
|
||||
val recordIterator = seekRecordList.iterator()
|
||||
while (recordIterator.hasNext()) {
|
||||
if ((current - recordIterator.next().recordTime) >= SEEK_RECORD_LIMIT_TIME) {
|
||||
recordIterator.remove()
|
||||
}
|
||||
}
|
||||
return seekRecordList.size
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正开始寻求帮助,实际就是请求接口
|
||||
*/
|
||||
private fun realSeekHelp() {
|
||||
Logger.d(TAG, "realSeekHelp")
|
||||
// 请求故障求助接口
|
||||
ShareControl.getInstance(context).mogoServiceApis.networkApi.create(ShareApiService::class.java, HttpConstant.getNetHost()).sendHelpSignal().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SubscribeImpl<BaseData>(RequestOptions.create(context)) {
|
||||
override fun onSuccess(o: BaseData?) {
|
||||
super.onSuccess(o)
|
||||
// todo 接口请求成功,需要同步v2x状态,通知adas,改变自车图标
|
||||
isSeekHelp = true
|
||||
seekRecordList.add(SeekRecord(SystemClock.elapsedRealtime()))
|
||||
seekListenerList.forEach {
|
||||
it.onSeekHelpSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
// 接口请求失败
|
||||
Logger.e(TAG, "上报求助失败,网络异常")
|
||||
e.printStackTrace()
|
||||
seekHelpFail()
|
||||
}
|
||||
|
||||
override fun onError(message: String?, code: Int) {
|
||||
super.onError(message, code)
|
||||
// 接口请求失败
|
||||
Logger.e(TAG, "上报求助失败")
|
||||
seekHelpFail()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun seekHelpFail() {
|
||||
isSeekHelp = false
|
||||
seekListenerList.forEach {
|
||||
it.onSeekHelpFail()
|
||||
}
|
||||
toast("求助上报失败,请稍后重试")
|
||||
aiAssist?.speakTTSVoice("求助上报失败,请稍后重试")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.mogo.module.share.net
|
||||
|
||||
import com.mogo.commons.data.BaseData
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.http.POST
|
||||
|
||||
/**
|
||||
* 分享用到的api接口
|
||||
*/
|
||||
interface ShareApiService {
|
||||
/**
|
||||
* 发起求助接口
|
||||
*/
|
||||
@POST("")
|
||||
fun sendHelpSignal(): Observable<BaseData>
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user