BadCase
增加被动录包
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.zhjt.mogo_core_function_devatools
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
@@ -86,8 +87,8 @@ class DevaToolsProvider : IDevaToolsProvider {
|
||||
BadCaseManager.initAiCollect(view)
|
||||
}
|
||||
|
||||
override fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel) {
|
||||
BadCaseManager.onReceiveBadCaseRecord(record)
|
||||
override fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel,activity: Activity) {
|
||||
BadCaseManager.onReceiveBadCaseRecord(record,activity)
|
||||
}
|
||||
|
||||
override fun showFeedbackWindow(ctx: Context) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.zhjt.mogo_core_function_devatools.badcase
|
||||
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
@@ -58,9 +59,6 @@ internal object BadCaseManager : LifecycleEventObserver {
|
||||
@Volatile
|
||||
private var dismissJob: Job? = null
|
||||
|
||||
@Volatile
|
||||
private var feedbackFloatShow = false
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private var channel: Channel<AutoPilotRecord> = Channel(Channel.RENDEZVOUS)
|
||||
get() = if (field.isClosedForReceive || field.isClosedForSend) {
|
||||
@@ -236,17 +234,20 @@ internal object BadCaseManager : LifecycleEventObserver {
|
||||
return oldT == 0L || newT == 0L || (newT - oldT >= 0 && (newT - oldT) < CASE_EXPIRE_DURATION)
|
||||
}
|
||||
|
||||
fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel) {
|
||||
if (feedbackFloatShow) {
|
||||
fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel,activity: Activity) {
|
||||
if(BadCaseConfig.windowNum>1){
|
||||
return
|
||||
}
|
||||
scope?.launch {
|
||||
val newRecord = record.toRecord()
|
||||
withContext(Dispatchers.IO) {
|
||||
presenter.insertRecord(newRecord)
|
||||
channel.send(newRecord)
|
||||
val passiveBadCaseWindow = PassiveBadCaseWindow(activity)
|
||||
passiveBadCaseWindow.setRecord(record.key.toString(),record.filename)
|
||||
passiveBadCaseWindow.setClickListener(object: PassiveBadCaseWindow.ClickListener{
|
||||
override fun closeWindow() {
|
||||
passiveBadCaseWindow.hideFloatWindow()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
passiveBadCaseWindow.showFloatWindow()
|
||||
|
||||
}
|
||||
|
||||
private fun CoroutineScope.showBadCaseInternal(record: AutoPilotRecord) = launch {
|
||||
@@ -311,31 +312,10 @@ internal object BadCaseManager : LifecycleEventObserver {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val listener = object : IGlobalStateChangeListener {
|
||||
override fun onShow(reminder: IReminder) {
|
||||
if (reminder.key().startsWith("FeedBackFloatWindow_")) {
|
||||
feedbackFloatShow = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHide(reminder: IReminder) {
|
||||
if (reminder.key().startsWith("FeedBackFloatWindow_")) {
|
||||
feedbackFloatShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Event) {
|
||||
if (event == ON_CREATE) {
|
||||
Reminder.registerGlobalStateChangeListener(listener)
|
||||
}
|
||||
if (event == ON_DESTROY) {
|
||||
Reminder.unRegisterGlobalStateChangeListener(listener)
|
||||
dismissJob?.takeIf { it.isActive }?.cancel()
|
||||
hideFloat = null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -177,9 +177,8 @@ class InitiativeBadCaseWindow constructor(activity: Activity) : View.OnTouchList
|
||||
}else{
|
||||
uploadAudio()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
tvInitiativeCancel.setOnClickListener {
|
||||
BadCaseConfig.windowNum--
|
||||
clickListener?.closeWindow()
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
package com.zhjt.mogo_core_function_devatools.badcase.biz
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.PixelFormat
|
||||
import android.os.CountDownTimer
|
||||
import android.os.Handler
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.widget.CheckBox
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.TextView
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.eagle.core.data.app.AppConfigInfo
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotCarStateListener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotRecordListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotCarStatusListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
|
||||
import com.mogo.eagle.core.utilcode.mogo.toast.TipToast
|
||||
import com.mogo.eagle.core.utilcode.util.AppUtils
|
||||
import com.mogo.eagle.core.utilcode.util.SizeUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.mogo.eagle.core.utilcode.util.TimeUtils
|
||||
import com.mogo.eagle.core.utilcode.util.TimeUtils.millis2String
|
||||
import com.zhidao.loglib.call.LogInfoManagerFactory
|
||||
import com.zhidao.loglib.upload.OnUploadListener
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseConfig
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.record.RecordManager
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import record_cache.RecordPanelOuterClass
|
||||
import java.io.File
|
||||
import java.lang.reflect.Field
|
||||
|
||||
/**
|
||||
* @author XuXinChao
|
||||
* @description BadCase被动录包
|
||||
* @since: 2022/7/17
|
||||
*/
|
||||
class PassiveBadCaseWindow constructor(activity: Activity) : View.OnTouchListener,
|
||||
IMoGoAutopilotCarStateListener, CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
companion object {
|
||||
const val TAG = "PassiveBadCaseWindow"
|
||||
}
|
||||
|
||||
private var mActivity: Activity = activity
|
||||
private var mWindowParams: WindowManager.LayoutParams? = null
|
||||
private var mWindowManager: WindowManager? = null
|
||||
private lateinit var mFloatLayout: View
|
||||
|
||||
private var audioStatus = false
|
||||
private var audioFileName:String?=null //录音文件名称
|
||||
|
||||
private var uploadReason: String = String() //上报原因,标签
|
||||
private var recordKey: String?=null //录制bag包key
|
||||
private var recordFileName: String?=null //录制文件包名
|
||||
private var longitude: Double?=null
|
||||
private var latitude: Double?=null
|
||||
|
||||
private var mInViewX = 0f
|
||||
private var mInViewY = 0f
|
||||
private var mDownInScreenX = 0f
|
||||
private var mDownInScreenY = 0f
|
||||
private var mInScreenX = 0f
|
||||
private var mInScreenY = 0f
|
||||
|
||||
private var clickListener: ClickListener? = null
|
||||
var countDownTimer: CountDownTimer?=null
|
||||
|
||||
private lateinit var tvPassiveNum: TextView
|
||||
private lateinit var tvPassiveTime: TextView
|
||||
private lateinit var tvPassiveIdentity: TextView
|
||||
|
||||
private lateinit var viewAudioButton: View
|
||||
private lateinit var tvAudioCountDown: TextView
|
||||
|
||||
private lateinit var tvPassiveReport: TextView
|
||||
private lateinit var tvPassiveCancel: TextView
|
||||
|
||||
private lateinit var flReasonLayout: FlexboxLayout
|
||||
|
||||
init {
|
||||
initFloatWindow();
|
||||
}
|
||||
|
||||
private val presenter by lazy {
|
||||
BadCasePresenter()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun initFloatWindow(){
|
||||
mFloatLayout = LayoutInflater.from(mActivity).inflate(R.layout.view_passive_bad_case, null) as View
|
||||
mFloatLayout.setOnTouchListener(this)
|
||||
tvPassiveNum = mFloatLayout.findViewById(R.id.tvPassiveNum)
|
||||
tvPassiveTime = mFloatLayout.findViewById(R.id.tvPassiveTime)
|
||||
tvPassiveIdentity = mFloatLayout.findViewById(R.id.tvPassiveIdentity)
|
||||
viewAudioButton = mFloatLayout.findViewById(R.id.viewAudioButton)
|
||||
tvAudioCountDown = mFloatLayout.findViewById(R.id.tvAudioCountDown)
|
||||
tvPassiveReport = mFloatLayout.findViewById(R.id.tvPassiveReport)
|
||||
tvPassiveCancel = mFloatLayout.findViewById(R.id.tvPassiveCancel)
|
||||
flReasonLayout = mFloatLayout.findViewById(R.id.flReasonLayout)
|
||||
tvPassiveNum.text = BadCaseConfig.windowNum.toString()
|
||||
BadCaseConfig.windowNum++
|
||||
tvPassiveTime.text = "时间:${millis2String(System.currentTimeMillis(),TimeUtils.getHourMinSecondFormat())}"
|
||||
tvPassiveIdentity.text = "身份:${BadCaseConfig.identity}"
|
||||
// 添加 ADAS车辆状态&定位 监听
|
||||
CallerAutopilotCarStatusListenerManager.addListener(TAG, this)
|
||||
viewAudioButton.setOnClickListener {
|
||||
audioStatus = !audioStatus
|
||||
setAudio(audioStatus)
|
||||
}
|
||||
|
||||
tvPassiveReport.setOnClickListener {
|
||||
if(uploadReason.isEmpty()){
|
||||
TipToast.shortTip("请选择至少一个Case")
|
||||
return@setOnClickListener
|
||||
}
|
||||
//点击上报时,如果没有停止录音则先停止录音
|
||||
//TODO 未结束录音,点击上报,未能上传语音成功
|
||||
if(audioStatus){
|
||||
audioStatus = !audioStatus
|
||||
setAudio(audioStatus)
|
||||
Handler().postDelayed({
|
||||
uploadAudio()
|
||||
},1000)
|
||||
}else{
|
||||
uploadAudio()
|
||||
}
|
||||
}
|
||||
|
||||
tvPassiveCancel.setOnClickListener {
|
||||
BadCaseConfig.windowNum--
|
||||
clickListener?.closeWindow()
|
||||
}
|
||||
|
||||
mWindowParams = WindowManager.LayoutParams()
|
||||
mWindowManager = mActivity.windowManager
|
||||
mWindowParams?.let {
|
||||
it.format = PixelFormat.RGBA_8888
|
||||
it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
it.gravity = Gravity.START or Gravity.TOP
|
||||
it.width = 924
|
||||
it.height = 668
|
||||
it.alpha = 1.0f
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAudio(status: Boolean){
|
||||
if(status){
|
||||
//开始录音
|
||||
audioFileName = "Audio_${System.currentTimeMillis()}_BadCase"
|
||||
RecordManager.getInstance().start(audioFileName)
|
||||
//更改录音按钮背景
|
||||
viewAudioButton.background = mActivity.getDrawable(R.drawable.bad_case_audio_select)
|
||||
tvAudioCountDown.visibility = View.VISIBLE
|
||||
//开始倒计时
|
||||
if(countDownTimer==null){
|
||||
countDownTimer = object : CountDownTimer(60000, 1000) {
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
tvAudioCountDown.text = "${millisUntilFinished/1000}S"
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
tvAudioCountDown.visibility = View.GONE
|
||||
//结束录音
|
||||
RecordManager.getInstance().stop()
|
||||
//更改录音按钮背景
|
||||
viewAudioButton.background = mActivity.getDrawable(R.drawable.bad_case_audio_normal)
|
||||
}
|
||||
}
|
||||
countDownTimer?.start()
|
||||
}
|
||||
}else{
|
||||
//结束倒计时
|
||||
countDownTimer?.cancel()
|
||||
countDownTimer?.onFinish()
|
||||
//将倒计时置空
|
||||
countDownTimer = null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun uploadAudio(){
|
||||
val singlePath = "/mnt/sdcard/mogo/DataCollection/${audioFileName}.wav"
|
||||
val file = File(singlePath)
|
||||
if(file.exists()){
|
||||
LogInfoManagerFactory.createAudioUpload(mActivity,"Audio",singlePath,
|
||||
object : OnUploadListener {
|
||||
override fun onUploadSuccess(filePath: String, downloadUrl: String) {
|
||||
CallerLogger.d("$M_DEVA$TAG", "语音文件上传成功:downloadUrl=$downloadUrl")
|
||||
//上传到服务器
|
||||
upload(downloadUrl)
|
||||
}
|
||||
|
||||
override fun onUploadFail(filePath: String) {
|
||||
TipToast.shortTip("上传语音文件失败")
|
||||
}
|
||||
})
|
||||
}else{
|
||||
//上传到服务器
|
||||
upload(null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将记录上传到服务器
|
||||
* @param downloadUrl 语音文件下载地址
|
||||
*/
|
||||
private fun upload(downloadUrl: String?){
|
||||
GlobalScope.launch{
|
||||
val uploadResult = presenter.upload(mutableMapOf<String, String>().also { itx ->
|
||||
itx["carLicense"] = AppConfigInfo.plateNumber?:"" //车牌号
|
||||
itx["filename"] = recordFileName?:"" //bag包文件地址
|
||||
itx["filesize"] = "0" //bag包文件大小
|
||||
itx["key"] = recordKey?:"" //key
|
||||
itx["reason"] = uploadReason //采集原因
|
||||
itx["duration"] = BadCaseConfig.totalDuration.toString() //采集时长,固定为20S
|
||||
itx["startTime"] = System.currentTimeMillis().toString() //上报时间(时间戳格式)
|
||||
itx["channel"] = "1" //渠道
|
||||
itx["carSn"] = MoGoAiCloudClientConfig.getInstance().sn //SN
|
||||
itx["userRole"] = BadCaseConfig.identity //采集者角色
|
||||
itx["audioUrl"] = downloadUrl?:"" //音频COS地址
|
||||
itx["mapVersion"] = BadCaseConfig.dockerVersion ?:"" //工控机版本
|
||||
itx["eyeVersion"] = AppUtils.getAppVersionName() //鹰眼版本
|
||||
itx["coordinate"] = "latitude:${latitude};longitude:${longitude}" //坐标
|
||||
|
||||
})
|
||||
if (uploadResult == null || uploadResult.code != 200) {
|
||||
TipToast.shortTip("上报失败")
|
||||
} else {
|
||||
TipToast.shortTip("上报成功")
|
||||
BadCaseConfig.windowNum--
|
||||
clickListener?.closeWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTouch(v: View?, motionEvent: MotionEvent?): Boolean {
|
||||
when (motionEvent?.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
// 获取相对View的坐标,即以此View左上角为原点
|
||||
mInViewX = motionEvent.x
|
||||
mInViewY = motionEvent.y
|
||||
// 获取相对屏幕的坐标,即以屏幕左上角为原点
|
||||
mDownInScreenX = motionEvent.rawX
|
||||
mDownInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
|
||||
mInScreenX = motionEvent.rawX
|
||||
mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
// 更新浮动窗口位置参数
|
||||
mInScreenX = motionEvent.rawX
|
||||
mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity)
|
||||
mWindowParams!!.x = (mInScreenX - mInViewX).toInt()
|
||||
mWindowParams!!.y = (mInScreenY - mInViewY).toInt()
|
||||
// 手指移动的时候更新小悬浮窗的位置
|
||||
mWindowManager!!.updateViewLayout(mFloatLayout, mWindowParams)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun showFloatWindow() {
|
||||
if (mFloatLayout.parent == null) {
|
||||
val metrics = DisplayMetrics()
|
||||
// 默认固定位置,靠屏幕右边缘的中间
|
||||
mWindowManager!!.defaultDisplay.getMetrics(metrics)
|
||||
mWindowParams!!.x = metrics.widthPixels
|
||||
mWindowParams!!.y = metrics.heightPixels / 2 - getSysBarHeight(mActivity)-350
|
||||
mWindowManager!!.addView(mFloatLayout, mWindowParams)
|
||||
}
|
||||
|
||||
GlobalScope.launch{
|
||||
presenter.loadBadCases(true).also {
|
||||
ThreadUtils.runOnUiThread {
|
||||
it.iterator().forEach {
|
||||
val checkBox = CheckBox(mActivity)
|
||||
checkBox.setTextColor(Color.WHITE)
|
||||
val lp = FlexboxLayout.LayoutParams(FlexboxLayout.LayoutParams.WRAP_CONTENT,
|
||||
FlexboxLayout.LayoutParams.WRAP_CONTENT)
|
||||
// lp.setMargins(
|
||||
// SizeUtils.dp2px(0f),
|
||||
// SizeUtils.dp2px(0f),
|
||||
// SizeUtils.dp2px(0f),
|
||||
// SizeUtils.dp2px(0f)
|
||||
// )
|
||||
checkBox.buttonDrawable = mActivity.resources.getDrawable(R.drawable.badcase_radio_button_style)
|
||||
checkBox.setPadding(SizeUtils.dp2px(12f),
|
||||
SizeUtils.dp2px(5f),
|
||||
SizeUtils.dp2px(10f),
|
||||
SizeUtils.dp2px(5f))
|
||||
checkBox.textSize = SizeUtils.sp2px(9f).toFloat()
|
||||
checkBox.text = it.reason
|
||||
checkBox.isChecked = it.isChecked
|
||||
checkBox.setOnCheckedChangeListener(this@PassiveBadCaseWindow)
|
||||
flReasonLayout.addView(checkBox,lp)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
|
||||
Log.i("onCheckedChanged","buttonView"+buttonView)
|
||||
Log.i("onCheckedChanged","isChecked"+isChecked)
|
||||
buttonView?.text?.let {
|
||||
if(isChecked){
|
||||
if(!uploadReason.contains(it)){
|
||||
uploadReason += it
|
||||
}
|
||||
}else{
|
||||
if(uploadReason.contains(it)){
|
||||
uploadReason.replace(it.toString(),"")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun hideFloatWindow() {
|
||||
// 移除 ADAS车辆状态&定位 监听
|
||||
CallerAutopilotCarStatusListenerManager.removeListener(TAG)
|
||||
if (mFloatLayout.parent != null) mWindowManager!!.removeView(mFloatLayout)
|
||||
}
|
||||
|
||||
// 获取系统状态栏高度
|
||||
private fun getSysBarHeight(activity: Activity): Int {
|
||||
val c: Class<*>
|
||||
val obj: Any
|
||||
val field: Field
|
||||
val x: Int
|
||||
var sbar = 0
|
||||
try {
|
||||
c = Class.forName("com.android.internal.R\$dimen")
|
||||
obj = c.newInstance()
|
||||
field = c.getField("status_bar_height")
|
||||
x = field.get(obj).toString().toInt()
|
||||
sbar = activity.resources.getDimensionPixelSize(x)
|
||||
} catch (e1: Exception) {
|
||||
e1.printStackTrace()
|
||||
}
|
||||
return sbar
|
||||
}
|
||||
|
||||
fun setRecord(key:String,fileName:String){
|
||||
recordKey = key
|
||||
recordFileName = fileName
|
||||
}
|
||||
|
||||
fun setClickListener(clickListener: ClickListener) {
|
||||
this.clickListener = clickListener
|
||||
}
|
||||
|
||||
interface ClickListener {
|
||||
fun closeWindow()
|
||||
}
|
||||
|
||||
override fun onAutopilotCarStateData(gnssInfo: MessagePad.GnssInfo?) {
|
||||
latitude = gnssInfo?.latitude
|
||||
longitude = gnssInfo?.longitude
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.mogo.eagle.core.widget.RoundConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="924px"
|
||||
android:layout_height="668px"
|
||||
app:roundLayoutRadius="40px"
|
||||
android:background="@color/module_switch_map_bg">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="113px"
|
||||
android:background="@drawable/ai_collect_title_bg"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPassiveNum"
|
||||
android:layout_width="120px"
|
||||
android:layout_height="113px"
|
||||
android:background="@drawable/icon_num_bg"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="46px"
|
||||
android:gravity="center"
|
||||
android:text="1"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPassiveTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toRightOf="@id/tvPassiveNum"
|
||||
app:layout_constraintTop_toTopOf="@id/tvPassiveNum"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvPassiveNum"
|
||||
android:text="时间:14:23:10"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="38px"
|
||||
android:layout_marginStart="@dimen/dp_50"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPassiveIdentity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="@id/tvPassiveNum"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvPassiveNum"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:text="身份:QA"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="38px"
|
||||
android:layout_marginEnd="@dimen/dp_50"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPassiveReport"
|
||||
android:layout_width="270px"
|
||||
android:layout_height="70px"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/tvPassiveCancel"
|
||||
android:background="@drawable/report_button_bg"
|
||||
android:text="上报"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="30px"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="@dimen/dp_40"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPassiveCancel"
|
||||
android:layout_width="270px"
|
||||
android:layout_height="70px"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/tvPassiveReport"
|
||||
android:text="取消"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="30px"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/cancel_button_bg"
|
||||
android:layout_marginBottom="@dimen/dp_40"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:id="@+id/viewAudioBg"
|
||||
android:layout_width="824px"
|
||||
android:layout_height="174px"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/tvPassiveReport"
|
||||
android:background="@drawable/bad_case_audio_bg"
|
||||
android:layout_marginBottom="@dimen/dp_40"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:id="@+id/viewAudioButton"
|
||||
android:layout_width="105px"
|
||||
android:layout_height="105px"
|
||||
app:layout_constraintLeft_toLeftOf="@id/viewAudioBg"
|
||||
app:layout_constraintRight_toRightOf="@id/viewAudioBg"
|
||||
app:layout_constraintTop_toTopOf="@id/viewAudioBg"
|
||||
app:layout_constraintBottom_toBottomOf="@id/viewAudioBg"
|
||||
android:background="@drawable/bad_case_audio_normal"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40px"
|
||||
android:layout_height="55px"
|
||||
android:src="@drawable/icon_audio"
|
||||
app:layout_constraintLeft_toLeftOf="@id/viewAudioButton"
|
||||
app:layout_constraintRight_toRightOf="@id/viewAudioButton"
|
||||
app:layout_constraintTop_toTopOf="@id/viewAudioButton"
|
||||
app:layout_constraintBottom_toBottomOf="@id/viewAudioButton"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAudioCountDown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="30px"
|
||||
app:layout_constraintTop_toTopOf="@id/viewAudioButton"
|
||||
app:layout_constraintBottom_toBottomOf="@id/viewAudioButton"
|
||||
app:layout_constraintLeft_toRightOf="@id/viewAudioButton"
|
||||
android:layout_marginStart="@dimen/dp_30"
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvPassiveNum"
|
||||
app:layout_constraintBottom_toTopOf="@id/viewAudioBg"
|
||||
android:layout_margin="@dimen/dp_30"
|
||||
>
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@+id/flReasonLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:alignContent="flex_start"
|
||||
app:alignItems="center"
|
||||
app:flexDirection="row"
|
||||
app:flexWrap="wrap"
|
||||
app:justifyContent="flex_start"
|
||||
/>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</com.mogo.eagle.core.widget.RoundConstraintLayout>
|
||||
Reference in New Issue
Block a user