视频组件
This commit is contained in:
@@ -78,6 +78,7 @@ class AlarmLogActivity : AppCompatActivity() {
|
|||||||
.setShowFullAnimation(true)
|
.setShowFullAnimation(true)
|
||||||
.setNeedShowWifiTip(false)
|
.setNeedShowWifiTip(false)
|
||||||
.setEnlargeImageRes(R.drawable.full_size)
|
.setEnlargeImageRes(R.drawable.full_size)
|
||||||
|
.setShrinkImageRes(R.drawable.full_screen)
|
||||||
.setBottomShowProgressBarDrawable(progressDrawable, thumbDrawable)
|
.setBottomShowProgressBarDrawable(progressDrawable, thumbDrawable)
|
||||||
.setVideoAllCallBack(object : GSYSampleCallBack() {
|
.setVideoAllCallBack(object : GSYSampleCallBack() {
|
||||||
override fun onPrepared(url: String?, vararg objects: Any?) {
|
override fun onPrepared(url: String?, vararg objects: Any?) {
|
||||||
@@ -91,6 +92,15 @@ class AlarmLogActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build(binding.exoPlayContextId)
|
.build(binding.exoPlayContextId)
|
||||||
|
binding.exoPlayContextId.backButton.setOnClickListener {
|
||||||
|
|
||||||
|
if (orientationUtils?.isLand == 1) {
|
||||||
|
// 当前全屏,先退出全屏
|
||||||
|
binding.exoPlayContextId.fullscreenButton.performClick()
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.exoPlayContextId.onControlVisibilityChanged = { show ->
|
binding.exoPlayContextId.onControlVisibilityChanged = { show ->
|
||||||
Log.e("GSY_TEST", "Activity收到回调 show=$show")
|
Log.e("GSY_TEST", "Activity收到回调 show=$show")
|
||||||
|
|||||||
@@ -1,47 +1,37 @@
|
|||||||
package com.example.defenseapplication.liveVideo
|
package com.example.defenseapplication.liveVideo
|
||||||
|
|
||||||
import android.Manifest
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.media.AudioManager
|
||||||
import android.media.MediaRecorder
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.animation.ScaleAnimation
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import chuangyuan.ycj.videolibrary.video.ExoUserPlayer
|
|
||||||
import com.example.defenseapplication.R
|
import com.example.defenseapplication.R
|
||||||
import com.example.defenseapplication.adapter.AlarmLogHorizontalAdapter
|
import com.example.defenseapplication.adapter.AlarmLogHorizontalAdapter
|
||||||
import com.example.defenseapplication.base.BaseActivity
|
import com.example.defenseapplication.base.BaseActivity
|
||||||
import com.example.defenseapplication.bean.DeviceAlarmBean
|
import com.example.defenseapplication.bean.DeviceAlarmBean
|
||||||
import com.example.defenseapplication.bean.DeviceAlarmResponse
|
|
||||||
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
|
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
|
||||||
import com.example.defenseapplication.utils.ActivityManager
|
import com.example.defenseapplication.utils.ActivityManager
|
||||||
import com.example.defenseapplication.utils.RetrofitNetwork
|
import com.example.defenseapplication.utils.RetrofitNetwork
|
||||||
|
import com.example.defenseapplication.view.MyGSYVideoPlayer
|
||||||
import com.gyf.immersionbar.ImmersionBar
|
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 kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import androidx.lifecycle.lifecycleScope
|
||||||
import java.io.IOException
|
import com.alibaba.sdk.android.emas.f
|
||||||
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
|
|
||||||
|
|
||||||
class LiveVideoActivity : BaseActivity() {
|
class LiveVideoActivity : BaseActivity() {
|
||||||
private lateinit var binding: LiveVideoActivityBinding
|
private lateinit var binding: LiveVideoActivityBinding
|
||||||
|
|
||||||
private lateinit var exoPlayerManager: ExoUserPlayer
|
|
||||||
private var isVoiceEnabled = false
|
private var isVoiceEnabled = false
|
||||||
private var isLightOn = 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 deviceId: String? = null
|
||||||
private var alarmList: MutableList<DeviceAlarmBean> = mutableListOf()
|
private var alarmList: MutableList<DeviceAlarmBean> = mutableListOf()
|
||||||
private var alarmAdapter: AlarmLogHorizontalAdapter? = null
|
private var alarmAdapter: AlarmLogHorizontalAdapter? = null
|
||||||
@@ -50,18 +40,8 @@ class LiveVideoActivity : BaseActivity() {
|
|||||||
private val pageSize = 10
|
private val pageSize = 10
|
||||||
private var hasMore = true
|
private var hasMore = true
|
||||||
private var isLoading = false
|
private var isLoading = false
|
||||||
private var isFirstLoad = true
|
|
||||||
|
private var orientationUtils: OrientationUtils? = null
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -83,47 +63,52 @@ class LiveVideoActivity : BaseActivity() {
|
|||||||
initAlarmRecyclerView()
|
initAlarmRecyclerView()
|
||||||
initListener()
|
initListener()
|
||||||
fetchAlarmList()
|
fetchAlarmList()
|
||||||
// onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
|
||||||
// override fun handleOnBackPressed() {
|
|
||||||
// if (exoPlayerManager.onBackPressed()) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// finish()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initVideoPlayer() {
|
private fun initVideoPlayer() {
|
||||||
val videoPlayerView = binding.exoPlayContextId
|
val videoUrl = "https://www.w3schools.com/html/movie.mp4"
|
||||||
|
|
||||||
exoPlayerManager = VideoPlayerManager.Builder(VideoPlayerManager.TYPE_PLAY_GESTURE, videoPlayerView)
|
orientationUtils = OrientationUtils(this, binding.exoPlayContextId)
|
||||||
.setPlayUri("https://media.w3.org/2010/05/sintel/trailer.mp4")
|
orientationUtils?.isEnable = true
|
||||||
.setPosition(0)
|
|
||||||
.addVideoInfoListener(object : VideoInfoListener {
|
GSYVideoOptionBuilder()
|
||||||
override fun onPlayStart(p0: Long) {
|
.setUrl(videoUrl)
|
||||||
Log.d("LiveVideoActivity", "视频开始播放")
|
.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 onQuitFullscreen(url: String?, vararg objects: Any?) {
|
||||||
}
|
super.onQuitFullscreen(url, *objects)
|
||||||
|
orientationUtils?.backToProtVideo()
|
||||||
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) {
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.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() {
|
private fun initAlarmRecyclerView() {
|
||||||
@@ -177,20 +162,15 @@ class LiveVideoActivity : BaseActivity() {
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.llVoice.setOnClickListener {
|
|
||||||
toggleVoice()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.llLight.setOnClickListener {
|
binding.llLight.setOnClickListener {
|
||||||
toggleLight()
|
isLightOn = !isLightOn
|
||||||
}
|
|
||||||
|
|
||||||
binding.llRecord.setOnClickListener {
|
if (isLightOn) {
|
||||||
toggleRecording()
|
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on_open)
|
||||||
}
|
} else {
|
||||||
|
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on)
|
||||||
binding.llAlarmLog.setOnClickListener {
|
}
|
||||||
Toast.makeText(this, R.string.view_alarm_log, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.xq.setOnClickListener {
|
binding.xq.setOnClickListener {
|
||||||
@@ -199,53 +179,6 @@ class LiveVideoActivity : BaseActivity() {
|
|||||||
intent.putExtra("from_live_video", true)
|
intent.putExtra("from_live_video", true)
|
||||||
startActivity(intent)
|
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) {
|
private fun fetchAlarmList(page: Int = 1) {
|
||||||
@@ -260,20 +193,13 @@ class LiveVideoActivity : BaseActivity() {
|
|||||||
)
|
)
|
||||||
Log.d("LiveVideoActivity", "总条数: ${response.total}, 当前页数据条数: ${response.rows.size}")
|
Log.d("LiveVideoActivity", "总条数: ${response.total}, 当前页数据条数: ${response.rows.size}")
|
||||||
val newData = response.rows
|
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) {
|
totalPage = if (response.total % pageSize == 0) {
|
||||||
response.total / pageSize
|
response.total / pageSize
|
||||||
} else {
|
} else {
|
||||||
response.total / pageSize + 1
|
response.total / pageSize + 1
|
||||||
}
|
}
|
||||||
isFirstLoad = false
|
|
||||||
|
|
||||||
if (page == 1) {
|
if (page == 1) {
|
||||||
alarmList.clear()
|
alarmList.clear()
|
||||||
hasMore = totalPage > 1
|
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() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
exoPlayerManager.onResume()
|
binding.exoPlayContextId.onVideoResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
exoPlayerManager.onPause()
|
binding.exoPlayContextId.onVideoPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
exoPlayerManager.onDestroy()
|
orientationUtils?.releaseListener()
|
||||||
|
binding.exoPlayContextId.release()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
exoPlayerManager.onConfigurationChanged(newConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -44,12 +44,10 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 视频播放区域 -->
|
<!-- 视频播放区域 -->
|
||||||
<chuangyuan.ycj.videolibrary.widget.VideoPlayerView
|
<com.example.defenseapplication.view.MyGSYVideoPlayer
|
||||||
android:id="@+id/exoPlayContextId"
|
android:id="@+id/exoPlayContextId"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="250dp"
|
android:layout_height="280dp"/>
|
||||||
android:background="@android:color/transparent"
|
|
||||||
app:use_controller="false"/>
|
|
||||||
|
|
||||||
<!-- 功能按钮区域 -->
|
<!-- 功能按钮区域 -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
Reference in New Issue
Block a user