diff --git a/.idea/misc.xml b/.idea/misc.xml
index 2dc54c489f..707ee6e613 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/AndroidManifest.xml b/modules/mogo-module-share/src/main/AndroidManifest.xml
index fb780d7be4..84394ab363 100644
--- a/modules/mogo-module-share/src/main/AndroidManifest.xml
+++ b/modules/mogo-module-share/src/main/AndroidManifest.xml
@@ -1,4 +1,7 @@
+
+
+
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareControl.java b/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareControl.java
index 4256364c5e..c5b20b8269 100644
--- a/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareControl.java
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareControl.java
@@ -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) {
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareVoiceCmdReceiver.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareVoiceCmdReceiver.kt
new file mode 100644
index 0000000000..589c66705d
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/ShareVoiceCmdReceiver.kt
@@ -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)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/VoiceCmdService.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/VoiceCmdService.kt
new file mode 100644
index 0000000000..ae1c6924c9
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/VoiceCmdService.kt
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/bean/SeekRecord.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/bean/SeekRecord.kt
new file mode 100644
index 0000000000..68a2057e9d
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/bean/SeekRecord.kt
@@ -0,0 +1,6 @@
+package com.mogo.module.share.bean
+
+/**
+ * 求助记录,recordTime建议使用SystemClock.elapsedRealtime记录,因为此时间主要是为了做时间差,而不是精确时间
+ */
+data class SeekRecord(val recordTime: Long)
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/HttpConstant.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/HttpConstant.kt
new file mode 100644
index 0000000000..efcafe37e9
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/HttpConstant.kt
@@ -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
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/ShareConstants.java b/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/ShareConstants.java
index 5f9a7b6385..139081e11f 100644
--- a/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/ShareConstants.java
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/constant/ShareConstants.java
@@ -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;
}
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/dialog/LaucherShareDialog.java b/modules/mogo-module-share/src/main/java/com/mogo/module/share/dialog/LaucherShareDialog.java
index fa9aa484db..1813680d2e 100644
--- a/modules/mogo-module-share/src/main/java/com/mogo/module/share/dialog/LaucherShareDialog.java
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/dialog/LaucherShareDialog.java
@@ -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();
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/manager/ISeekHelpListener.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/manager/ISeekHelpListener.kt
new file mode 100644
index 0000000000..f338eb0533
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/manager/ISeekHelpListener.kt
@@ -0,0 +1,16 @@
+package com.mogo.module.share.manager
+
+/**
+ * 寻求帮助结果监听
+ */
+interface ISeekHelpListener {
+ /**
+ * 寻求帮助成功
+ */
+ fun onSeekHelpSuccess()
+
+ /**
+ * 寻求帮助失败
+ */
+ fun onSeekHelpFail()
+}
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/manager/SeekHelpManager.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/manager/SeekHelpManager.kt
new file mode 100644
index 0000000000..6e5ca38fbd
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/manager/SeekHelpManager.kt
@@ -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()
+ private val seekListenerList = mutableListOf()
+ 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(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("求助上报失败,请稍后重试")
+ }
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/java/com/mogo/module/share/net/ShareApiService.kt b/modules/mogo-module-share/src/main/java/com/mogo/module/share/net/ShareApiService.kt
new file mode 100644
index 0000000000..40aa03baaf
--- /dev/null
+++ b/modules/mogo-module-share/src/main/java/com/mogo/module/share/net/ShareApiService.kt
@@ -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
+
+}
\ No newline at end of file
diff --git a/modules/mogo-module-share/src/main/res/layout/launcher_dialog_share_2.xml b/modules/mogo-module-share/src/main/res/layout/launcher_dialog_share_2.xml
new file mode 100644
index 0000000000..8a3346c594
--- /dev/null
+++ b/modules/mogo-module-share/src/main/res/layout/launcher_dialog_share_2.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file