From d60322cbc22230072a9706c4076824e500b57d22 Mon Sep 17 00:00:00 2001 From: maxinyu Date: Fri, 5 Jun 2026 09:33:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=86=E9=A2=91=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../liveVideo/AlarmLogActivity.kt | 10 + .../liveVideo/LiveVideoActivity.kt | 314 ++++-------------- app/src/main/res/drawable/full_screen.png | Bin 3160 -> 1247 bytes .../main/res/layout/live_video_activity.xml | 6 +- 4 files changed, 74 insertions(+), 256 deletions(-) diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt index 1da339f..9a3ff95 100644 --- a/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt @@ -78,6 +78,7 @@ class AlarmLogActivity : AppCompatActivity() { .setShowFullAnimation(true) .setNeedShowWifiTip(false) .setEnlargeImageRes(R.drawable.full_size) + .setShrinkImageRes(R.drawable.full_screen) .setBottomShowProgressBarDrawable(progressDrawable, thumbDrawable) .setVideoAllCallBack(object : GSYSampleCallBack() { override fun onPrepared(url: String?, vararg objects: Any?) { @@ -91,6 +92,15 @@ class AlarmLogActivity : AppCompatActivity() { } }) .build(binding.exoPlayContextId) + binding.exoPlayContextId.backButton.setOnClickListener { + + if (orientationUtils?.isLand == 1) { + // 当前全屏,先退出全屏 + binding.exoPlayContextId.fullscreenButton.performClick() + } else { + finish() + } + } binding.exoPlayContextId.onControlVisibilityChanged = { show -> Log.e("GSY_TEST", "Activity收到回调 show=$show") 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 cf740a1..1502ccb 100644 --- a/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt @@ -1,47 +1,37 @@ package com.example.defenseapplication.liveVideo -import android.Manifest +import android.content.Context import android.content.Intent -import android.content.pm.PackageManager -import android.media.MediaRecorder +import android.media.AudioManager import android.os.Bundle import android.util.Log -import android.view.animation.ScaleAnimation +import android.view.View import android.widget.Toast -import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import chuangyuan.ycj.videolibrary.video.ExoUserPlayer import com.example.defenseapplication.R import com.example.defenseapplication.adapter.AlarmLogHorizontalAdapter import com.example.defenseapplication.base.BaseActivity import com.example.defenseapplication.bean.DeviceAlarmBean -import com.example.defenseapplication.bean.DeviceAlarmResponse import com.example.defenseapplication.databinding.LiveVideoActivityBinding import com.example.defenseapplication.utils.ActivityManager import com.example.defenseapplication.utils.RetrofitNetwork +import com.example.defenseapplication.view.MyGSYVideoPlayer import com.gyf.immersionbar.ImmersionBar +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack +import com.shuyu.gsyvideoplayer.utils.OrientationUtils import kotlinx.coroutines.launch -import java.io.File -import java.io.IOException -import android.content.res.Configuration -import androidx.activity.OnBackPressedCallback -import chuangyuan.ycj.videolibrary.listener.VideoInfoListener -import chuangyuan.ycj.videolibrary.video.VideoPlayerManager -import android.view.View -import com.bumptech.glide.Glide +import androidx.lifecycle.lifecycleScope +import com.alibaba.sdk.android.emas.f class LiveVideoActivity : BaseActivity() { private lateinit var binding: LiveVideoActivityBinding - private lateinit var exoPlayerManager: ExoUserPlayer private var isVoiceEnabled = false private var isLightOn = false - private var isRecording = false - private var mediaRecorder: MediaRecorder? = null - private var micPulseAnimation: ScaleAnimation? = null private var deviceId: String? = null private var alarmList: MutableList = mutableListOf() private var alarmAdapter: AlarmLogHorizontalAdapter? = null @@ -50,18 +40,8 @@ class LiveVideoActivity : BaseActivity() { private val pageSize = 10 private var hasMore = true private var isLoading = false - private var isFirstLoad = true - - private val requestPermissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestPermission() - ) { isGranted -> - if (isGranted) { - startRecordingMode() - } else { - Toast.makeText(this, R.string.recording_permission_needed, Toast.LENGTH_SHORT).show() - isRecording = false - } - } + + private var orientationUtils: OrientationUtils? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -83,47 +63,52 @@ class LiveVideoActivity : BaseActivity() { initAlarmRecyclerView() initListener() fetchAlarmList() -// onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { -// override fun handleOnBackPressed() { -// if (exoPlayerManager.onBackPressed()) { -// return -// } -// finish() -// } -// }) } private fun initVideoPlayer() { - val videoPlayerView = binding.exoPlayContextId + val videoUrl = "https://www.w3schools.com/html/movie.mp4" - exoPlayerManager = VideoPlayerManager.Builder(VideoPlayerManager.TYPE_PLAY_GESTURE, videoPlayerView) - .setPlayUri("https://media.w3.org/2010/05/sintel/trailer.mp4") - .setPosition(0) - .addVideoInfoListener(object : VideoInfoListener { - override fun onPlayStart(p0: Long) { - Log.d("LiveVideoActivity", "视频开始播放") + orientationUtils = OrientationUtils(this, binding.exoPlayContextId) + orientationUtils?.isEnable = true + + GSYVideoOptionBuilder() + .setUrl(videoUrl) + .setCacheWithPlay(false) + .setRotateViewAuto(true) + .setLockLand(false) + .setShowFullAnimation(true) + .setNeedShowWifiTip(false) + .setEnlargeImageRes(R.drawable.full_size) + .setShrinkImageRes(R.drawable.full_screen) + + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onPrepared(url: String?, vararg objects: Any?) { + super.onPrepared(url, *objects) + orientationUtils?.isEnable = true } - override fun onLoadingChanged() { - } - - override fun onPlayerError(p0: com.google.android.exoplayer2.ExoPlaybackException?) { - Toast.makeText(this@LiveVideoActivity, "播放失败", Toast.LENGTH_SHORT).show() - } - - override fun onPlayEnd() { - Log.d("LiveVideoActivity", "播放结束") - } - - override fun isPlaying(p0: Boolean) { - } - - fun onRepeatModeChanged(p0: Int) { + override fun onQuitFullscreen(url: String?, vararg objects: Any?) { + super.onQuitFullscreen(url, *objects) + orientationUtils?.backToProtVideo() } }) - .create() + .build(binding.exoPlayContextId) - exoPlayerManager.startPlayer() + + + + binding.exoPlayContextId.startPlayLogic() + binding.exoPlayContextId.fullscreenButton.setOnClickListener { + orientationUtils?.resolveByClick() + + binding.exoPlayContextId.startWindowFullscreen(this, true, true)?.let { fullPlayer -> + if (fullPlayer is MyGSYVideoPlayer) { + fullPlayer.onControlVisibilityChanged = { show -> + Log.e("GSY_TEST", "全屏回调 show=$show") + } + } + } + } } private fun initAlarmRecyclerView() { @@ -177,20 +162,15 @@ class LiveVideoActivity : BaseActivity() { startActivity(intent) } - binding.llVoice.setOnClickListener { - toggleVoice() - } binding.llLight.setOnClickListener { - toggleLight() - } + isLightOn = !isLightOn - binding.llRecord.setOnClickListener { - toggleRecording() - } - - binding.llAlarmLog.setOnClickListener { - Toast.makeText(this, R.string.view_alarm_log, Toast.LENGTH_SHORT).show() + if (isLightOn) { + binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on_open) + } else { + binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on) + } } binding.xq.setOnClickListener { @@ -199,53 +179,6 @@ class LiveVideoActivity : BaseActivity() { intent.putExtra("from_live_video", true) startActivity(intent) } - - // 控制台方向按钮点击事件 - binding.ivUp.setOnClickListener { - handleDirectionClick("up") - } - binding.ivDown.setOnClickListener { - handleDirectionClick("down") - } - binding.ivLeft.setOnClickListener { - handleDirectionClick("left") - } - binding.ivRight.setOnClickListener { - handleDirectionClick("right") - } - - // 触摸反馈 - setTouchFeedback(binding.ivUp) - setTouchFeedback(binding.ivDown) - setTouchFeedback(binding.ivLeft) - setTouchFeedback(binding.ivRight) - } - - private fun setTouchFeedback(view: View) { - view.setOnTouchListener { v, event -> - when (event.action) { - android.view.MotionEvent.ACTION_DOWN -> { - v.scaleX = 0.9f - v.scaleY = 0.9f - } - android.view.MotionEvent.ACTION_UP, android.view.MotionEvent.ACTION_CANCEL -> { - v.scaleX = 1.0f - v.scaleY = 1.0f - } - } - false - } - } - - private fun handleDirectionClick(direction: String) { - val directionText = when (direction) { - "up" -> getString(R.string.direction_up) - "down" -> getString(R.string.direction_down) - "left" -> getString(R.string.direction_left) - "right" -> getString(R.string.direction_right) - else -> "" - } - } private fun fetchAlarmList(page: Int = 1) { @@ -260,20 +193,13 @@ class LiveVideoActivity : BaseActivity() { ) Log.d("LiveVideoActivity", "总条数: ${response.total}, 当前页数据条数: ${response.rows.size}") val newData = response.rows - if (newData.isEmpty()) { - } else { - newData.take(3).forEachIndexed { index, item -> - Log.d("LiveVideoActivity", " 第${index + 1}条 - id: ${item.id}, categoryName: ${item.categoryName}, createTime: ${item.createTime}") - } - } - + totalPage = if (response.total % pageSize == 0) { response.total / pageSize } else { response.total / pageSize + 1 } - isFirstLoad = false - + if (page == 1) { alarmList.clear() hasMore = totalPage > 1 @@ -288,135 +214,19 @@ class LiveVideoActivity : BaseActivity() { } } - private fun toggleVoice() { - isVoiceEnabled = !isVoiceEnabled - - if (isVoiceEnabled) { - Glide.with(this).asGif().load(com.example.defenseapplication.R.drawable.voice_on_open).into(binding.ivVoice) - } else { - binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice) - } - } - - private fun toggleLight() { - isLightOn = !isLightOn - - if (isLightOn) { - binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on_open) - } else { - binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on) - } - } - - private fun toggleRecording() { - if (!isRecording) { - if (checkRecordAudioPermission()) { - startRecordingMode() - } else { - requestRecordAudioPermission() - } - } else { - 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 - - Glide.with(this).asGif().load(com.example.defenseapplication.R.drawable.voice_on_open).into(binding.ivVoice) - isVoiceEnabled = true - - startVoiceRecording() - } - - 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() - } - - 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, R.string.recording_start_failed, Toast.LENGTH_SHORT).show() - } - } - } - - private fun stopVoiceRecording() { - mediaRecorder?.let { - try { - it.stop() - it.release() - } catch (e: Exception) { - e.printStackTrace() - } - mediaRecorder = null - } - } - override fun onResume() { super.onResume() - exoPlayerManager.onResume() + binding.exoPlayContextId.onVideoResume() } override fun onPause() { super.onPause() - exoPlayerManager.onPause() + binding.exoPlayContextId.onVideoPause() } override fun onDestroy() { super.onDestroy() - exoPlayerManager.onDestroy() + orientationUtils?.releaseListener() + binding.exoPlayContextId.release() } - - override fun onConfigurationChanged(newConfig: Configuration) { - super.onConfigurationChanged(newConfig) - exoPlayerManager.onConfigurationChanged(newConfig) - } -} +} \ No newline at end of file diff --git a/app/src/main/res/drawable/full_screen.png b/app/src/main/res/drawable/full_screen.png index cb91da8f8b1d4556a33e6e5751d95dfb73b9169a..968590fe10ed0613923678c4195e8ba59f5340f4 100644 GIT binary patch literal 1247 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 N2nNl;y2Z+y_kT!TUV{Jt diff --git a/app/src/main/res/layout/live_video_activity.xml b/app/src/main/res/layout/live_video_activity.xml index 1f3e639..9256a0f 100644 --- a/app/src/main/res/layout/live_video_activity.xml +++ b/app/src/main/res/layout/live_video_activity.xml @@ -44,12 +44,10 @@ - + android:layout_height="280dp"/>