diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a119749..3cde424 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,8 @@
+
+
@@ -23,6 +25,12 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DefenseApplication">
+
+
@@ -52,7 +60,7 @@
android:exported="false" />
+ android:exported="false" />
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt
new file mode 100644
index 0000000..dacd45e
--- /dev/null
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt
@@ -0,0 +1,29 @@
+package com.example.defenseapplication.liveVideo
+
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.AlarmLogActivityBinding
+import com.gyf.immersionbar.ImmersionBar
+
+class AlarmLogActivity : AppCompatActivity() {
+ private lateinit var binding: AlarmLogActivityBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = AlarmLogActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ ImmersionBar.with(this)
+ .statusBarDarkFont(true)
+ .titleBar(binding.topBar)
+ .init()
+ initListener()
+ }
+
+ private fun initListener() {
+ binding.btnBack.setOnClickListener {
+ finish()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt
index b4eb20d..4ceb1af 100644
--- a/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt
@@ -1,24 +1,38 @@
package com.example.defenseapplication.liveVideo
+import android.Manifest
+import android.content.Intent
import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
import android.media.AudioManager
import android.media.MediaPlayer
+import android.media.MediaRecorder
import android.net.Uri
+import android.os.Build
import android.os.Bundle
+import android.os.Environment
import android.view.SurfaceHolder
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
+import android.view.animation.Animation
+import android.view.animation.LinearInterpolator
+import android.view.animation.ScaleAnimation
import android.widget.Toast
import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.test.isEnabled
+import androidx.core.content.ContextCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
import com.gyf.immersionbar.ImmersionBar
import com.gyf.immersionbar.ktx.destroyImmersionBar
+import java.io.File
import java.io.IOException
+private const val TAG = "LiveVideoActivity"
+
class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
private lateinit var binding: LiveVideoActivityBinding
@@ -28,11 +42,24 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
private var isVoiceEnabled = false
private var isLightOn = false
private var isRecording = false
+ private var mediaRecorder: MediaRecorder? = null
+ private var micPulseAnimation: ScaleAnimation? = null
private var videoWidth = 0
private var videoHeight = 0
private val testVideoUrl = "https://vjs.zencdn.net/v/oceans.mp4"
+
+ private val requestPermissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ startRecordingMode()
+ } else {
+ Toast.makeText(this, "需要录音权限才能使用控制功能", Toast.LENGTH_SHORT).show()
+ isRecording = false
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -140,7 +167,8 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
}
binding.ivMenu.setOnClickListener {
- Toast.makeText(this, "菜单", Toast.LENGTH_SHORT).show()
+ val intent = Intent(this, SettingsActivity::class.java)
+ startActivity(intent)
}
binding.ivFullscreen.setOnClickListener {
@@ -166,6 +194,12 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
binding.llAlarmLog.setOnClickListener {
Toast.makeText(this, "查看告警日志", Toast.LENGTH_SHORT).show()
}
+
+ // 点击xq箭头跳转到AlarmLogActivity
+ binding.xq.setOnClickListener {
+ val intent = Intent(this, AlarmLogActivity::class.java)
+ startActivity(intent)
+ }
}
private fun togglePlayPause() {
@@ -270,14 +304,124 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
}
private fun toggleRecording() {
- isRecording = !isRecording
-
- if (isRecording) {
- binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open)
- Toast.makeText(this, "开始录像", Toast.LENGTH_SHORT).show()
+ if (!isRecording) {
+ if (checkRecordAudioPermission()) {
+ startRecordingMode()
+ } else {
+ requestRecordAudioPermission()
+ }
} else {
- binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy)
- Toast.makeText(this, "停止录像", Toast.LENGTH_SHORT).show()
+ stopRecordingMode()
+ }
+ }
+
+ private fun checkRecordAudioPermission(): Boolean {
+ return ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.RECORD_AUDIO
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+
+ private fun requestRecordAudioPermission() {
+ requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
+ }
+
+ private fun startRecordingMode() {
+ isRecording = true
+
+ binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open)
+ // 隐藏告警日志区域,显示控制台区域
+ binding.llAlarmLog.visibility = View.GONE
+ binding.consoleBar.visibility = View.VISIBLE
+
+ // 麦克风切换成开启状态
+ binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_open)
+ isVoiceEnabled = true
+
+ // 启动语音录制
+ startVoiceRecording()
+
+ // 启动麦克风脉冲动画
+ startMicPulseAnimation()
+
+ Toast.makeText(this, "开始控制模式", Toast.LENGTH_SHORT).show()
+ }
+
+ private fun stopRecordingMode() {
+ isRecording = false
+
+ binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy)
+ // 显示告警日志区域,隐藏控制台区域
+ binding.llAlarmLog.visibility = View.VISIBLE
+ binding.consoleBar.visibility = View.GONE
+
+ // 麦克风切换成关闭状态
+ binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice)
+ isVoiceEnabled = false
+
+ // 停止语音录制
+ stopVoiceRecording()
+
+ // 停止麦克风脉冲动画
+ stopMicPulseAnimation()
+
+ Toast.makeText(this, "停止控制模式", Toast.LENGTH_SHORT).show()
+ }
+
+ private fun startMicPulseAnimation() {
+ micPulseAnimation = ScaleAnimation(
+ 1.0f, 1.3f,
+ 1.0f, 1.3f,
+ Animation.RELATIVE_TO_SELF, 0.5f,
+ Animation.RELATIVE_TO_SELF, 0.5f
+ ).apply {
+ duration = 500
+ repeatCount = Animation.INFINITE
+ repeatMode = Animation.REVERSE
+ interpolator = LinearInterpolator()
+ }
+ binding.ivVoice.startAnimation(micPulseAnimation)
+ }
+
+ private fun stopMicPulseAnimation() {
+ micPulseAnimation?.let {
+ binding.ivVoice.clearAnimation()
+ micPulseAnimation = null
+ }
+ }
+
+ private fun startVoiceRecording() {
+ mediaRecorder = MediaRecorder().apply {
+ setAudioSource(MediaRecorder.AudioSource.MIC)
+ setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
+ val outputDir = getExternalFilesDir(null) ?: filesDir
+ val audioDir = File(outputDir, "audio")
+ if (!audioDir.exists()) {
+ audioDir.mkdirs()
+ }
+ val outputFile = File(audioDir, "voice_record_${System.currentTimeMillis()}.3gp")
+ setOutputFile(outputFile.absolutePath)
+ setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
+
+ try {
+ prepare()
+ start()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ Toast.makeText(this@LiveVideoActivity, "录音启动失败", Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ private fun stopVoiceRecording() {
+ mediaRecorder?.let {
+ try {
+ it.stop()
+ it.release()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ mediaRecorder = null
}
}
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt
new file mode 100644
index 0000000..57d06ec
--- /dev/null
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt
@@ -0,0 +1,25 @@
+package com.example.defenseapplication.liveVideo
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.example.defenseapplication.databinding.SettingsActivityBinding
+import com.gyf.immersionbar.ImmersionBar
+
+class SettingsActivity : AppCompatActivity() {
+
+ private lateinit var binding: SettingsActivityBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = SettingsActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ // ImmersionBar核心调用,沉浸式
+ ImmersionBar.with(this)
+ .statusBarDarkFont(true)
+ .titleBar(binding.topBar)
+ .init()
+ binding.ivBack.setOnClickListener {
+ finish()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/back_white.png b/app/src/main/res/drawable/back_white.png
new file mode 100644
index 0000000..39089f2
Binary files /dev/null and b/app/src/main/res/drawable/back_white.png differ
diff --git a/app/src/main/res/drawable/console.png b/app/src/main/res/drawable/console.png
new file mode 100644
index 0000000..98ac9fb
Binary files /dev/null and b/app/src/main/res/drawable/console.png differ
diff --git a/app/src/main/res/drawable/delete.png b/app/src/main/res/drawable/delete.png
new file mode 100644
index 0000000..668b0a1
Binary files /dev/null and b/app/src/main/res/drawable/delete.png differ
diff --git a/app/src/main/res/drawable/download.png b/app/src/main/res/drawable/download.png
new file mode 100644
index 0000000..b6bc9d0
Binary files /dev/null and b/app/src/main/res/drawable/download.png differ
diff --git a/app/src/main/res/drawable/expand.png b/app/src/main/res/drawable/expand.png
new file mode 100644
index 0000000..b203b4d
Binary files /dev/null and b/app/src/main/res/drawable/expand.png differ
diff --git a/app/src/main/res/drawable/mute.png b/app/src/main/res/drawable/mute.png
new file mode 100644
index 0000000..a9a43da
Binary files /dev/null and b/app/src/main/res/drawable/mute.png differ
diff --git a/app/src/main/res/drawable/start.png b/app/src/main/res/drawable/start.png
new file mode 100644
index 0000000..b058f91
Binary files /dev/null and b/app/src/main/res/drawable/start.png differ
diff --git a/app/src/main/res/layout/alarm_log_activity.xml b/app/src/main/res/layout/alarm_log_activity.xml
new file mode 100644
index 0000000..2c05859
--- /dev/null
+++ b/app/src/main/res/layout/alarm_log_activity.xml
@@ -0,0 +1,364 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+>-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/live_video_activity.xml b/app/src/main/res/layout/live_video_activity.xml
index 298ff10..63960b2 100644
--- a/app/src/main/res/layout/live_video_activity.xml
+++ b/app/src/main/res/layout/live_video_activity.xml
@@ -187,6 +187,25 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/settings_activity.xml b/app/src/main/res/layout/settings_activity.xml
new file mode 100644
index 0000000..c23ce63
--- /dev/null
+++ b/app/src/main/res/layout/settings_activity.xml
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 65904ee..92102b5 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -13,5 +13,6 @@
#99000000
#E7E7E7
#F9F9F9
+ #03A9F4
\ No newline at end of file