增加语音部分业务

This commit is contained in:
qiji4215 2023-04-28 16:16:17 +08:00
parent 977b4b54da
commit defcfb66fb
54 changed files with 1203 additions and 19 deletions

View File

@ -29,6 +29,7 @@
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 读取缓存数据 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--android:largeHeap="true" 大内存 128M -->
<application
android:name=".OMQSApplication"

View File

@ -32,6 +32,11 @@ class Constant {
*/
lateinit var USER_DATA_PATH: String
/**
* 用户附件数据目录
*/
lateinit var USER_DATA_ATTACHEMNT_PATH: String
/**
* 离线地图目录
*/
@ -49,6 +54,8 @@ class Constant {
const val DEBUG = true
var IS_VIDEO_SPEED by kotlin.properties.Delegates.notNull<Boolean>()
const val message_status_late = "预约,待发送"
const val message_status_send_over = "已发送"
const val message_version_right_off = "1" //立即发送

View File

@ -0,0 +1,43 @@
package com.navinfo.omqs.bean
import java.io.Serializable
import java.util.*
class Attachment(filename: String, type: Int) : Serializable,
Cloneable {
//内容
var filename: String = ""
//标识 默认照片0 录音1
var type: Int
override fun toString(): String {
return "TipsAttachment{" +
"filename='" + filename + '\'' +
", type=" + type +
'}'
}
override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val that = o as Attachment
return type == that.type &&
filename == that.filename
}
override fun hashCode(): Int {
return Objects.hash(filename, type)
}
@kotlin.Throws(CloneNotSupportedException::class)
public override fun clone(): Any {
return super.clone()
}
init {
this.filename = filename
this.type = type
}
}

View File

@ -0,0 +1,23 @@
package com.navinfo.omqs.bean
import java.io.Serializable
class ChatMsgEntity : Serializable, Cloneable {
var voiceUri //声音存储地址
: String? = null
var voiceTimeLong //声音时间长度
: String? = null
var name //声音名字
: String? = null
var isDelete //是否被删除
= false
@kotlin.Throws(CloneNotSupportedException::class)
public override fun clone(): Any {
return super.clone()
}
companion object {
private val TAG: String = ChatMsgEntity::class.java.getSimpleName()
}
}

View File

@ -37,6 +37,7 @@ public class CheckPermissionsActivity extends BaseActivity {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
};
private static final int PERMISSON_REQUESTCODE = 0;
@ -51,6 +52,7 @@ public class CheckPermissionsActivity extends BaseActivity {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO,
BACKGROUND_LOCATION_PERMISSION
};
}

View File

@ -156,12 +156,17 @@ class LoginViewModel @Inject constructor(
* 创建用户目录
*/
private fun createUserFolder(context: Context, userId: String) {
Constant.IS_VIDEO_SPEED = false
Constant.USER_ID = userId
Constant.VERSION_ID = userId
Constant.USER_DATA_PATH = Constant.DATA_PATH + Constant.USER_ID + "/" + Constant.VERSION_ID
Constant.USER_DATA_ATTACHEMNT_PATH = Constant.USER_DATA_PATH + "/attachment/"
// 在SD卡创建用户目录解压资源等
val userFolder = File(Constant.USER_DATA_PATH)
if (!userFolder.exists()) userFolder.mkdirs()
//创建附件目录
val userAttachmentFolder = File(Constant.USER_DATA_ATTACHEMNT_PATH)
if (!userAttachmentFolder.exists()) userAttachmentFolder.mkdirs()
// 初始化Realm
Realm.init(context.applicationContext)
val password = "encryp".encodeToByteArray().copyInto(ByteArray(64))

View File

@ -1,7 +1,12 @@
package com.navinfo.omqs.ui.activity.map
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.navigation.findNavController
@ -52,6 +57,26 @@ class MainActivity : BaseActivity() {
//给xml传递viewModel对象
binding.viewModel = viewModel
binding.mainActivityVoice.setOnTouchListener(object : View.OnTouchListener {
@RequiresApi(Build.VERSION_CODES.Q)
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
Log.e("qj",event?.action.toString())
when (event?.action) {
MotionEvent.ACTION_DOWN ->{
voiceOnTouchStart()//Do Something
Log.e("qj","voiceOnTouchStart")
}
MotionEvent.ACTION_UP ->{
voiceOnTouchStop()//Do Something
Log.e("qj","voiceOnTouchStop")
}
}
return v?.onTouchEvent(event) ?: true
}
})
viewModel.liveDataQsRecordIdList.observe(this) {
//处理页面跳转
viewModel.navigation(this, it)
@ -68,8 +93,8 @@ class MainActivity : BaseActivity() {
mapController.locationLayerHandler.setNiLocationListener(NiLocationListener {
//ToastUtils.showLong("定位${it.longitude}")
binding!!.viewModel!!.addSaveTrace(it)
binding!!.viewModel!!.startSaveTraceThread(this)
})
binding!!.viewModel!!.startSaveTraceThread(this)
//显示轨迹图层
// mapController.layerManagerHandler.showNiLocationLayer(Constant.DATA_PATH+ SystemConstant.USER_ID+"/trace.sqlite")
mapController.layerManagerHandler.showNiLocationLayer()
@ -110,8 +135,19 @@ class MainActivity : BaseActivity() {
* 点击录音按钮
*/
fun voiceOnclick() {
val naviController = findNavController(R.id.main_activity_right_fragment)
naviController.navigate(R.id.EvaluationResultFragment)
/* val naviController = findNavController(R.id.main_activity_right_fragment)
naviController.navigate(R.id.EvaluationResultFragment)*/
}
fun voiceOnTouchStart(){
binding!!.viewModel!!.startSoundMetter(this,mapController.locationLayerHandler.getCurrentNiLocation(),binding.mainActivityVoice)
}
@RequiresApi(Build.VERSION_CODES.Q)
fun voiceOnTouchStop(){
if(Constant.IS_VIDEO_SPEED){
binding!!.viewModel!!.stopSoundMeter()
}
}
// override fun onBackPressed() {

View File

@ -1,12 +1,24 @@
package com.navinfo.omqs.ui.activity.map
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.graphics.drawable.AnimationDrawable
import android.graphics.drawable.BitmapDrawable
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.PopupWindow
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.navigation.findNavController
import com.blankj.utilcode.util.ToastUtils
import com.navinfo.collect.library.data.dao.impl.TraceDataBase
import com.navinfo.collect.library.data.entity.NiLocation
import com.navinfo.collect.library.map.NIMapController
@ -17,10 +29,15 @@ import com.navinfo.omqs.Constant
import com.navinfo.omqs.R
import com.navinfo.omqs.ui.dialog.CommonDialog
import com.navinfo.omqs.ui.manager.TakePhotoManager
import com.navinfo.omqs.util.DateTimeUtil
import com.navinfo.omqs.util.SoundMeter
import com.navinfo.omqs.util.SpeakMode
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.RealmSet
import org.oscim.core.GeoPoint
import org.videolan.libvlc.LibVlcUtil
import java.io.File
import java.util.*
import javax.inject.Inject
/**
@ -28,14 +45,23 @@ import javax.inject.Inject
*/
@HiltViewModel
class MainViewModel @Inject constructor(
private val mapController: NIMapController,
private val mapController: NIMapController
) : ViewModel() {
val liveDataQsRecordIdList = MutableLiveData<List<String>>()
private var mCameraDialog: CommonDialog? = null
//语音窗体
private var pop: PopupWindow? = null
private var mSpeakMode: SpeakMode? = null
private var niLocationList: MutableList<NiLocation> = ArrayList<NiLocation>()
//录音图标
var volume: ImageView? = null
var mSoundMeter: SoundMeter? = null
init {
mapController.markerHandle.setOnQsRecordItemClickListener(object :
OnQsRecordItemClickListener {
@ -43,6 +69,7 @@ class MainViewModel @Inject constructor(
liveDataQsRecordIdList.value = list
}
})
}
/**
@ -61,8 +88,6 @@ class MainViewModel @Inject constructor(
Log.e("qj", LibVlcUtil.hasCompatibleCPU(context).toString())
//ToastUtils.showShort("点击了相机")
if (mCameraDialog == null) {
mCameraDialog = CommonDialog(
context,
@ -100,11 +125,15 @@ class MainViewModel @Inject constructor(
Thread(Runnable {
try {
while (true) {
if (niLocationList != null && niLocationList.size > 0) {
var niLocation = niLocationList[0]
val geometry = GeometryTools.createGeometry(GeoPoint(niLocation.latitude,niLocation.longitude))
val geometry = GeometryTools.createGeometry(
GeoPoint(
niLocation.latitude,
niLocation.longitude
)
)
val tileX = RealmSet<Int>()
GeometryToolsKt.getTileXByGeometry(geometry.toString(), tileX)
val tileY = RealmSet<Int>()
@ -118,11 +147,16 @@ class MainViewModel @Inject constructor(
}
}
TraceDataBase.getDatabase(context, Constant.USER_DATA_PATH + "/trace.sqlite").niLocationDao.insert(niLocation)
TraceDataBase.getDatabase(
context,
Constant.USER_DATA_PATH + "/trace.sqlite"
).niLocationDao.insert(niLocation)
val list = TraceDataBase.getDatabase(
context,
Constant.USER_DATA_PATH + "/trace.sqlite"
).niLocationDao.findAll()
niLocationList.remove(niLocation)
Log.e("qj", "saveTrace==${niLocationList.size}")
Log.e("qj", "saveTrace==${niLocationList.size}===${list.size}")
}
Thread.sleep(30)
@ -141,6 +175,90 @@ class MainViewModel @Inject constructor(
}
}
fun startSoundMetter(context: Context, niLocation: NiLocation?, v: View) {
if (niLocation == null) {
ToastUtils.showLong("未获取到GPS信息请检查GPS是否正常")
//停止录音动画
if (pop != null && pop!!.isShowing())
pop!!.dismiss();
return;
}
if(mSpeakMode==null){
mSpeakMode = SpeakMode(context as Activity?)
}
//语音识别动画
if (pop == null) {
pop = PopupWindow()
pop!!.width = ViewGroup.LayoutParams.MATCH_PARENT
pop!!.height = ViewGroup.LayoutParams.WRAP_CONTENT
pop!!.setBackgroundDrawable(BitmapDrawable())
val view = View.inflate(context, R.layout.cv_card_voice_rcd_hint_window, null)
pop!!.contentView = view
volume = view.findViewById(R.id.volume)
}
pop!!.update()
Constant.IS_VIDEO_SPEED = true
//录音动画
//录音动画
if (pop != null) {
pop!!.showAtLocation(v, Gravity.CENTER, 0, 0)
}
volume!!.setBackgroundResource(R.drawable.pop_voice_img)
val animation = volume!!.background as AnimationDrawable
animation.start()
val name: String = DateTimeUtil.getTimeSSS().toString() + ".m4a"
if (mSoundMeter == null) {
mSoundMeter = SoundMeter()
}
mSoundMeter!!.setmListener(object : SoundMeter.OnSoundMeterListener {
@RequiresApi(Build.VERSION_CODES.Q)
override fun onSuccess(filePath: String?) {
if (!TextUtils.isEmpty(filePath) && File(filePath).exists()) {
if (File(filePath) == null || File(filePath).length() < 1600) {
ToastUtils.showLong("语音时间太短,无效!")
mSpeakMode!!.speakText("语音时间太短,无效")
stopSoundMeter()
return
}
}
mSpeakMode!!.speakText("结束录音")
//获取右侧fragment容器
val naviController = (context as Activity).findNavController(R.id.main_activity_right_fragment)
val bundle = Bundle()
bundle.putString("filePath", filePath)
naviController.navigate(R.id.EvaluationResultFragment, bundle)
}
@RequiresApi(api = Build.VERSION_CODES.Q)
override fun onfaild(message: String?) {
ToastUtils.showLong("录制失败!")
mSpeakMode!!.speakText("录制失败")
stopSoundMeter()
}
})
mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name)
ToastUtils.showLong("开始录音")
mSpeakMode!!.speakText("开始录音")
}
//停止语音录制
@RequiresApi(api = Build.VERSION_CODES.Q)
fun stopSoundMeter() {
//先重置标识,防止按钮抬起时触发语音结束
Constant.IS_VIDEO_SPEED = false
if (mSoundMeter != null && mSoundMeter!!.isStartSound()) {
mSoundMeter!!.stop()
}
if (pop != null && pop!!.isShowing) pop!!.dismiss()
}
fun navigation(activity: MainActivity, list: List<String>) {
//获取右侧fragment容器
val naviController = activity.findNavController(R.id.main_activity_right_fragment)

View File

@ -7,9 +7,11 @@ import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.navigation.NavOptions
import androidx.navigation.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentEvaluationResultBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
@ -17,15 +19,26 @@ import dagger.hilt.android.AndroidEntryPoint
class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
private lateinit var binding: FragmentEvaluationResultBinding
private val viewModel by shareViewModels<EvaluationResultViewModel>("QsRecode")
private val adapter: SoundtListAdapter by lazy {
SoundtListAdapter()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_evaluation_result, container, false)
binding.fragment = this
val layoutManager = LinearLayoutManager(context)
binding.viewModel = viewModel
binding.lifecycleOwner = this
//// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能
binding.evaluationVoiceRecyclerview.setHasFixedSize(true)
binding.evaluationVoiceRecyclerview.layoutManager = layoutManager
binding.evaluationVoiceRecyclerview.adapter = adapter
viewModel.listDataChatMsgEntityList.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
viewModel.getChatMsgEntityList()
return binding.root
}

View File

@ -1,12 +1,17 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.Attachment
import com.navinfo.omqs.bean.ChatMsgEntity
import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.db.RoomAppDatabase
import dagger.hilt.android.lifecycle.HiltViewModel
@ -14,7 +19,6 @@ import io.realm.Realm
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.locationtech.jts.geom.Point
import java.util.*
import javax.inject.Inject
@ -47,9 +51,12 @@ class EvaluationResultViewModel @Inject constructor(
*/
val liveDataRightTypeList = MutableLiveData<List<RightBean>>()
var liveDataQsRecordBean = MutableLiveData<QsRecordBean>()
var listDataChatMsgEntityList = MutableLiveData<MutableList<ChatMsgEntity>>()
var listDataAttachmentList = MutableLiveData<MutableList<Attachment>>()
var oldBean: QsRecordBean? = null
init {
@ -274,4 +281,22 @@ class EvaluationResultViewModel @Inject constructor(
}
}
}
/**
* 查询问题类型列表
*/
@RequiresApi(Build.VERSION_CODES.N)
fun getChatMsgEntityList() {
val chatMsgEntityList: MutableList<ChatMsgEntity> = ArrayList()
liveDataQsRecordBean.value!!.attachments.forEach{
//1 录音
if(it.type==1){
val chatMsgEntity = ChatMsgEntity()
chatMsgEntity.name = it.filename
chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH
chatMsgEntityList.add(chatMsgEntity)
}
}
listDataChatMsgEntityList.postValue(chatMsgEntityList)
}
}

View File

@ -0,0 +1,241 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.graphics.drawable.AnimationDrawable
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioTrack
import android.media.MediaPlayer
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.navinfo.omqs.R
import com.navinfo.omqs.bean.ChatMsgEntity
import com.navinfo.omqs.databinding.AdapterSoundListBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
import java.io.*
/**
* 语音 RecyclerView 适配器
*
* RecycleView ViewHolder 中监听 ViewModel LiveData然后此时传递的 lifecycleOwner 是对应的 Fragment由于 ViewHolder 的生命周期是比 Fragment 短的所以当 ViewHolder 销毁时由于 Fragment Lifecycle 还没有结束此时 ViewHolder 会发生内存泄露监听的 LiveData 没有解绑
* 这种场景下有两种解决办法
*使用 LiveData observeForever 然后在 ViewHolder 销毁前手动调用 removeObserver
*使用 LifecycleRegistry ViewHolder 分发生命周期(这里使用了这个)
*/
class SoundtListAdapter(
) : BaseRecyclerViewAdapter<ChatMsgEntity>() {
//媒体播放器
private val mMediaPlayer = MediaPlayer()
//媒体播放器
private var md: MediaPlayer? = null
private var mAudioTrack: AudioTrack? = null
//录音结束后,右侧显示图片
private var animView: View? = null
//录音时动画效果
private var animaV: AnimationDrawable? = null
private var itemClick: OnItemClickListner? = null
//最大宽度
private val maxWidth = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding =
AdapterSoundListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseViewHolder(viewBinding)
}
override fun onViewRecycled(holder: BaseViewHolder) {
super.onViewRecycled(holder)
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val binding: AdapterSoundListBinding =
holder.viewBinding as AdapterSoundListBinding
val entity = data[position]
//tag 方便onclick里拿到数据
holder.tag = entity.name.toString()
holder.viewBinding.tvTime.isSelected = entity.isDelete
holder.viewBinding.rlSoundContent.isSelected = entity.isDelete
holder.viewBinding.ivSoundAnim.setBackgroundResource(R.drawable.icon_sound_03)
if (itemClick != null) {
holder.viewBinding.rlSoundContent.setOnClickListener {
itemClick!!.onItemClick(it.findViewById<View>(R.id.rl_sound_content), position)
}
}
//mixWidth
if (!TextUtils.isEmpty(entity.name)) {
if (entity.name.indexOf(".pcm") > 0) {
val file: File = File(entity.voiceUri + entity.name)
if (file != null) {
val time = (file.length() / 16000).toInt()
val layoutParams: ViewGroup.LayoutParams =
holder.viewBinding.rlSoundContent.getLayoutParams()
layoutParams.width = 115 + time * 10
layoutParams.width =
if (layoutParams.width > layoutParams.width) maxWidth else layoutParams.width
holder.viewBinding.rlSoundContent.setLayoutParams(layoutParams)
holder.viewBinding.tvTime.text = time.toString() + "\""
}
} else {
try {
md = MediaPlayer()
md.reset()
md.setDataSource(entity.getVoiceUri() + entity.getName())
md.prepare()
} catch (e: Exception) {
// TODO Auto-generated catch block
e.printStackTrace()
}
var time =
if (entity.getVoiceTimeLong() == null) md!!.duration.toString() + "" else entity.getVoiceTimeLong()
.toString() + ""
if (!TextUtils.isEmpty(time)) {
val i = md!!.duration / 1000
time = i.toString() + "\""
val layoutParams: ViewGroup.LayoutParams =
holder.viewBinding.rlSoundContent.getLayoutParams()
layoutParams.width = 115 + i * 10
layoutParams.width =
if (layoutParams.width > layoutParams.width) maxWidth else layoutParams.width
holder.viewBinding.rlSoundContent.setLayoutParams(layoutParams)
}
holder.viewBinding.tvTime.text = time
md!!.release()
}
}
override fun getItemViewRes(position: Int): Int {
return R.layout.adapter_sound_list
}
/**
* 播放某段录音
*
* @param view 显示动画
* @param index 录音在集合中索引
*/
fun setPlayerIndex(view: View, index: Int) {
val imageV = view.findViewById<View>(R.id.iv_sound_anim) as ImageView
val width = view.width
if (animView != null) {
animaV?.stop()
animView!!.setBackgroundResource(R.drawable.icon_sound_03)
}
animView = imageV
val entity: ChatMsgEntity = data.get(index)
playMusic(entity.voiceUri + entity.name, imageV)
}
/**
* 播放录音
*
* @param name 录音名称
* @Description
*/
private fun playMusic(name: String, imageV: ImageView) {
imageV.setBackgroundResource(R.drawable.sound_anim)
animaV = imageV.background as AnimationDrawable
animaV!!.start()
if (name.indexOf(".pcm") > 0) {
audioTrackPlay(name, imageV)
} else {
mediaPlayer(name, imageV)
}
}
private fun mediaPlayer(name: String, imageV: ImageView) {
try {
if (mMediaPlayer.isPlaying) {
mMediaPlayer.stop()
}
mMediaPlayer.reset()
mMediaPlayer.setDataSource(name)
mMediaPlayer.prepare()
mMediaPlayer.start()
//播放结束
mMediaPlayer.setOnCompletionListener {
animaV!!.stop()
imageV.setBackgroundResource(R.drawable.icon_sound_03)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun audioTrackPlay(name: String, imageV: ImageView) {
var dis: DataInputStream? = null
try {
//从音频文件中读取声音
dis = DataInputStream(BufferedInputStream(FileInputStream(name)))
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
//最小缓存区
val bufferSizeInBytes = AudioTrack.getMinBufferSize(
16000,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT
)
//创建AudioTrack对象 依次传入 :流类型、采样率与采集的要一致、音频通道采集是IN 播放时OUT、量化位数、最小缓冲区、模式
if (mAudioTrack != null) {
mAudioTrack!!.stop()
mAudioTrack!!.release()
mAudioTrack = null
}
mAudioTrack = AudioTrack(
AudioManager.STREAM_MUSIC,
16000,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSizeInBytes,
AudioTrack.MODE_STREAM
)
val data = ByteArray(bufferSizeInBytes)
mAudioTrack!!.play() //开始播放
while (true) {
var i = 0
try {
while (dis!!.available() > 0 && i < data.size) {
data[i] = dis.readByte() //录音时write Byte 那么读取时就该为readByte要相互对应
i++
}
} catch (e: IOException) {
// TODO Auto-generated catch block
e.printStackTrace()
}
mAudioTrack!!.write(data, 0, data.size)
if (i != bufferSizeInBytes) //表示读取完了
{
break
}
}
mAudioTrack!!.stop() //停止播放
mAudioTrack!!.release() //释放资源
mAudioTrack = null
imageV.post {
animaV?.stop()
imageV.setBackgroundResource(R.drawable.icon_sound_03)
}
}
fun setOnItemClickListener(clickListner: OnItemClickListner) {
itemClick = clickListner
}
interface OnItemClickListner {
fun onItemClick(view: View?, postion: Int)
}
}

View File

@ -198,7 +198,7 @@ class TaskListAdapter(
}
override fun getItemViewRes(position: Int): Int {
return R.layout.adapter_offline_map_city
return R.layout.adapter_task_list
}
}

View File

@ -0,0 +1,161 @@
package com.navinfo.omqs.util;
import android.media.MediaRecorder;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.IOException;
/**
* 录音接口
*/
public class SoundMeter {
static final private double EMA_FILTER = 0.6;
private static final String TAG = "SoundMeter";
private String mFilePath;
private MediaRecorder mRecorder = null;
private double mEMA = 0.0;
//监听
private OnSoundMeterListener mListener;
//是否开启了语音录制
private boolean isStartSound;
/**
* 开始录音
*
* @param name 录音文件保存路径
*/
public void start(final String name) {
mFilePath = name;
isStartSound = false;
//执行录音操作
if (!Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED) || TextUtils.isEmpty(name)) {
if(mListener!=null)
mListener.onfaild("权限失败或者文件名称错误");
return;
}
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mRecorder.setOutputFile(name);
Log.w(TAG, "录音" + name);
try {
mRecorder.prepare();
mRecorder.start();
mEMA = 0.0;
isStartSound = true;
} catch (IllegalStateException e) {
if(mListener!=null)
mListener.onfaild(e.getMessage());
if (mRecorder != null)
mRecorder.release();
//启动异常释放资源
isStartSound = false;
mRecorder = null;
System.out.print(e.getMessage());
} catch (IOException e) {
System.out.print(e.getMessage());
if(mListener!=null)
mListener.onfaild(e.getMessage());
//启动异常释放资源
isStartSound = false;
if (mRecorder != null)
mRecorder.release();
mRecorder = null;
}finally {
}
}
}
/**
* 结束录音接释放录音对象
*/
public void stop() {
isStartSound = false;
try {
if (mRecorder != null) {
mRecorder.stop();
}
if(new File(mFilePath).exists()){
if(mListener!=null)
mListener.onSuccess(mFilePath);
}
} catch (Exception e) {
if(mListener!=null)
mListener.onfaild(e.getMessage());
} finally {
if (mRecorder != null)
mRecorder.release();
mRecorder = null;
}
}
/**
* 停止录音
*/
public void pause() {
if (mRecorder != null) {
mRecorder.stop();
}
}
/**
* 开始录音
*/
public void start() {
if (mRecorder != null) {
mRecorder.start();
}
}
/**
* 获取录音基准值
*
* @return
*/
public double getAmplitude() {
if (mRecorder != null)
return (mRecorder.getMaxAmplitude() / 2700.0);
else
return 0;
}
/**
* 获取EMA基准值
*
* @return
*/
public double getAmplitudeEMA() {
double amp = getAmplitude();
mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
return mEMA;
}
public OnSoundMeterListener getmListener() {
return mListener;
}
public void setmListener(OnSoundMeterListener mListener) {
this.mListener = mListener;
}
//是否开启了语音录制
public boolean isStartSound(){
return isStartSound;
}
//录音监听
public interface OnSoundMeterListener{
public void onSuccess(String filePath);
public void onfaild(String message);
}
}

View File

@ -0,0 +1,129 @@
package com.navinfo.omqs.util;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.Toast;
import com.blankj.utilcode.util.ToastUtils;
import com.navinfo.omqs.Constant;
import com.navinfo.omqs.R;
import java.io.File;
public class SoundRecordeUtils {
private static SoundRecordeUtils instance;
private SoundMeter mSensor; // 系统录音组件
private PopupWindow pop;
private ImageView volume;
private SpeakMode mSpeakMode;
private Activity mActivity;
public static SoundRecordeUtils getInstance(Activity context) {
if (instance == null) {
instance = new SoundRecordeUtils(context);
}
return instance;
}
public SoundRecordeUtils(Activity mContext) {
this.mActivity = mContext;
mSpeakMode = new SpeakMode(mContext);
initVoicePop();
}
private void initVoicePop() {
//语音识别动画
pop = new PopupWindow();
pop.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
pop.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
pop.setBackgroundDrawable(new BitmapDrawable());
View view = View.inflate(mActivity, R.layout.cv_card_voice_rcd_hint_window, null);
pop.setContentView(view);
pop.update();
volume = (ImageView) view.findViewById(R.id.volume);
}
//启动录音
public String startSoundMeter(View v, SoundRecordeCallback soundRecordeCallback, boolean isRemind/*是否需要默认语音提醒开始和结束录音*/) {
//录音动画
if (pop != null)
pop.showAtLocation(v, Gravity.CENTER, 0, 0);
volume.setBackgroundResource(R.drawable.pop_voice_img);
AnimationDrawable animation = (AnimationDrawable) volume.getBackground();
animation.start();
final String name = DateTimeUtil.getTimeSSS() + ".m4a";
if (mSensor == null) {
mSensor = new SoundMeter();
}
mSensor.setmListener(new SoundMeter.OnSoundMeterListener() {
@Override
public void onSuccess(String filePath) {
if (isRemind) {
mSpeakMode.speakText("结束录音");
}
if (soundRecordeCallback!=null) {
soundRecordeCallback.onSuccess(filePath, name);
}
}
@Override
public void onfaild(String message) {
if (isRemind) {
ToastUtils.showLong("录制失败!");
mSpeakMode.speakText("录制失败");
}
if (soundRecordeCallback!=null) {
soundRecordeCallback.onfaild(message);
}
}
});
//增加下目录创建防止由于目录导致无法录制文件
if (!new File(Constant.USER_DATA_ATTACHEMNT_PATH).exists()) {
new File(Constant.USER_DATA_ATTACHEMNT_PATH).mkdirs();
}
if (mSensor.isStartSound()) {
ToastUtils.showLong("已自动结束上一段录音");
mSpeakMode.speakText("已自动结束上一段录音");
return null;
}
//启动定时器
mSensor.start(Constant.USER_DATA_ATTACHEMNT_PATH + name);
if (isRemind) {
ToastUtils.showLong("开始录音");
mSpeakMode.speakText("开始录音");
}
return name;
}
//判断是否启动了录音
public boolean isStartSound(){
if(mSensor!=null){
return mSensor.isStartSound();
}
return false;
}
//停止语音录制
public void stopSoundMeter() {
//先重置标识防止按钮抬起时触发语音结束
if (mSensor != null && mSensor.isStartSound()) {
mSensor.stop();
}
if (pop != null && pop.isShowing())
pop.dismiss();
}
public interface SoundRecordeCallback{
public void onSuccess(String filePath, String fileName);
public void onfaild(String message);
}
}

View File

@ -0,0 +1,149 @@
package com.navinfo.omqs.util;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import com.navinfo.omqs.ui.dialog.FirstDialog;
import java.util.HashMap;
import java.util.Locale;
//语音类
public class SpeakMode extends Activity implements TextToSpeech.OnInitListener{
private Activity mActivity;
private TextToSpeech mTextToSpeech;//TTS对象
private int status;
private int MY_DATA_CHECK_CODE = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0x11:
try {
HashMap<String, String> params = new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_STREAM, "STREAM_NOTIFICATION");//设置播放类型音频流类型
mTextToSpeech.speak(msg.obj + "", TextToSpeech.QUEUE_ADD, params);//将这个发音任务添加当前任务之后
//BaseToast.makeText(mActivity,msg.obj+"",Toast.LENGTH_LONG).show();
mTextToSpeech.playSilence(100, TextToSpeech.QUEUE_ADD, params);//间隔多长时间
} catch (Exception e) {
}
break;
}
}
};
public SpeakMode(Activity activity) {
mActivity = activity;
if (mActivity != null && !mActivity.isFinishing())
this.mTextToSpeech = new TextToSpeech(this.mActivity, this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
}
public void setData(String json) {
}
@Override
public void onInit(int status) {
this.status = status;
if (this.mTextToSpeech != null) {
int result = this.mTextToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
if (mActivity != null && !mActivity.isFinishing()) {
FirstDialog firstDialog = new FirstDialog(mActivity);
firstDialog.setTitle("提示");
firstDialog.setMessage("设备不支持语音播报,请先下载语音助手。");
firstDialog.setConfirmListener(new FirstDialog.OnClickListener() {
@Override
public void onClick(Dialog dialog, int which) {
dialog.dismiss();
}
});
firstDialog.setNegativeView(View.GONE);
firstDialog.show();
}
}
}
Log.i("TextToSpeechDemo", String.valueOf(status));
}
//读语音处理
public void speakText(final String message) {
new Thread(new Runnable() {
@Override
public void run() {
if (mTextToSpeech != null) {
int result = mTextToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
} else {
if (mTextToSpeech != null && mTextToSpeech.isSpeaking()) {
while (mTextToSpeech.isSpeaking()) {
try {
//增加播报停止解决不能播报最新内容问题
mTextToSpeech.stop();
Thread.sleep(100);
} catch (Exception e) {
}
}
}
Message msg = new Message();
msg.what = 0x11;
msg.obj = message;
mHandler.sendMessage(msg);
}
}
}
}).start();
}
public void stopSpeek() {
try {
if (this.mTextToSpeech != null && this.mTextToSpeech.isSpeaking()) {
this.mTextToSpeech.stop();
}
} catch (Exception e) {
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#FF3030"></item>
<item android:state_selected="true" android:color="#FF3030"></item>
<item android:color="#1ABBFE"></item>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/icon_select_sound_press"/>
<item android:state_selected="true" android:drawable="@drawable/icon_select_sound_press"/>
<item android:drawable="@drawable/icon_select_sound_defaule"/>
</selector>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="@color/black" />
<stroke
android:width="1dp"
android:color="@color/deepskyblue" />
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"
>
<item android:drawable="@drawable/amp7" android:duration="90" />
<item android:drawable="@drawable/amp1" android:duration="90" />
<item android:drawable="@drawable/amp2" android:duration="90" />
<item android:drawable="@drawable/amp3" android:duration="90" />
<item android:drawable="@drawable/amp4" android:duration="90" />
<item android:drawable="@drawable/amp5" android:duration="90" />
<item android:drawable="@drawable/amp6" android:duration="90" />
<item android:drawable="@drawable/amp7" android:duration="90" />
</animation-list>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="@drawable/icon_sound_03" android:duration="200" />
<item android:drawable="@drawable/icon_sound_02" android:duration="200" />
<item android:drawable="@drawable/icon_sound_01" android:duration="200" />
</animation-list>

View File

@ -63,7 +63,6 @@
android:layout_height="48dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="120dp"
android:onClick="@{()->mainActivity.voiceOnclick()}"
android:src="@drawable/baseline_keyboard_voice_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/ivory"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
android:paddingBottom="5dp"
tools:context="com.navinfo.omqs.ui.fragment.evaluationresult.SoundListAdapter">
<LinearLayout
android:id="@+id/rl_sound_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_select_sound_xml"
android:gravity="center_vertical"
android:minWidth="50dp"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="6dp"
android:layout_toRightOf="@id/tv_chatcontent"
android:gravity="left|center"
android:lineSpacingExtra="2dp"
android:text=""
android:textColor="@color/font_blue_reg"
android:textSize="15sp" />
<ImageView
android:id="@+id/iv_sound_anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/sound_anim" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
>
<LinearLayout
android:id="@+id/rl_sound_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:minWidth="50dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:background="@drawable/bg_select_sound_xml" >
<TextView
android:layout_marginLeft="10dp"
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="6dp"
android:layout_toRightOf="@id/tv_chatcontent"
android:gravity="left|center"
android:lineSpacingExtra="2dp"
android:text=""
android:textColor="@color/font_blue_reg"
android:textSize="15sp" />
<ImageView
android:id="@+id/iv_sound_anim"
android:background="@drawable/sound_anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center" >
<LinearLayout
android:id="@+id/voice_rcd_hint_rcding"
android:layout_width="wrap_content"
android:layout_height="140.0dip"
android:gravity="bottom|center"
android:orientation="horizontal"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/drawable_bg_blue_frame_black_bg_4_radius"
android:orientation="horizontal"
>
<ImageView
android:background="@drawable/pop_voice_img"
android:scaleType="center"
android:id="@+id/volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/del_re"
android:layout_width="140.0dip"
android:layout_height="140.0dip"
android:layout_marginLeft="10.0dip"
android:background="@drawable/voice_rcd_cancel_bg_focused"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="取消"
android:textColor="#ffffff"
android:textSize="13.0dip" />
<ImageView
android:id="@+id/sc_img1"
android:layout_width="75.0dip"
android:layout_height="75.0dip"
android:layout_marginTop="12.0dip"
android:src="@drawable/rcd_cancel_icon"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/voice_rcd_hint_tooshort"
android:layout_width="140.0dip"
android:layout_height="140.0dip"
android:background="@drawable/voice_rcd_hint_bg"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/voice_to_short" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15.0dip"
android:text="时间太短"
android:textColor="#ffffff" />
</LinearLayout>
</LinearLayout>

View File

@ -125,10 +125,16 @@
android:layout_margin="5dp"
android:background="@color/gray_121" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="多媒体" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/evaluation_voice_recyclerview"
android:layout_width="match_parent"
android:layout_height="80dp" />
android:layout_height="120dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -43,4 +43,7 @@ public interface INiLocationDao {
@Query("SELECT * FROM niLocation where tilex>=:minx and tilex<=:maxx and tiley>=:miny and tiley <=:maxy and time>=:startTime and time<=:endTime")
List<NiLocation> timeTofindList(int minx, int maxx, int miny, int maxy,long startTime,long endTime);
@Query("SELECT * FROM niLocation")
List<NiLocation> findAll();
}

View File

@ -1,6 +1,7 @@
package com.navinfo.collect.library.data.entity
import com.navinfo.collect.library.utils.GeometryToolsKt
import com.navinfo.omqs.bean.Attachment
import io.realm.RealmObject
import io.realm.RealmSet
import io.realm.annotations.PrimaryKey
@ -86,6 +87,8 @@ open class QsRecordBean @JvmOverloads constructor(
*/
var guideGeometry: String = "",
var attachments:RealmSet<Attachment>,
) : RealmObject() {
fun copy(): QsRecordBean {
@ -104,6 +107,7 @@ open class QsRecordBean @JvmOverloads constructor(
confirmUserId = confirmUserId,
t_lifecycle = t_lifecycle,
t_status = t_status,
attachments = attachments,
)
qs.geometry = geometry
return qs

View File

@ -53,7 +53,8 @@ public class MapLifeNiLocationTileDataSource implements ITileDataSource {
if(mEndTime!=0){
list = TraceDataBase.getDatabase(mCon, dbName).getNiLocationDao().timeTofindList(xStart, xEnd, yStart, yEnd,mStartTime,mEndTime);
}else{
list = TraceDataBase.getDatabase(mCon, dbName).getNiLocationDao().findList(xStart, xEnd, yStart, yEnd);
//list = TraceDataBase.getDatabase(mCon, dbName).getNiLocationDao().findList(xStart, xEnd, yStart, yEnd);
list = TraceDataBase.getDatabase(mCon, dbName).getNiLocationDao().findAll();
}
Log.e("qj","query"+(list==null?0:list.size())+"==="+xStart+"==="+xEnd+"==="+yStart+"==="+yEnd);