mirror of
https://github.com/home-assistant/android
synced 2024-10-06 16:19:38 +00:00
Update ExoPlayer usage (#3760)
* Switch to StyledPlayerView for migration * Migrate to media3 for ExoPlayer * Replace deprecated code * Restore/customize layout to ExoPlayer v2
This commit is contained in:
parent
77141c254b
commit
49f3080b9e
|
@ -159,11 +159,9 @@ dependencies {
|
||||||
implementation(libs.biometric)
|
implementation(libs.biometric)
|
||||||
implementation(libs.webkit)
|
implementation(libs.webkit)
|
||||||
|
|
||||||
implementation(libs.exoplayer.core)
|
implementation(libs.bundles.media3)
|
||||||
implementation(libs.exoplayer.hls)
|
"fullImplementation"(libs.media3.datasource.cronet)
|
||||||
implementation(libs.exoplayer.ui)
|
"minimalImplementation"(libs.media3.datasource.cronet) {
|
||||||
"fullImplementation"(libs.extension.cronet)
|
|
||||||
"minimalImplementation"(libs.extension.cronet) {
|
|
||||||
exclude(group = "com.google.android.gms", module = "play-services-cronet")
|
exclude(group = "com.google.android.gms", module = "play-services-cronet")
|
||||||
}
|
}
|
||||||
"minimalImplementation"(libs.cronet.embedded)
|
"minimalImplementation"(libs.cronet.embedded)
|
||||||
|
|
|
@ -42,15 +42,15 @@ import android.webkit.WebResourceRequest
|
||||||
import android.webkit.WebResourceResponse
|
import android.webkit.WebResourceResponse
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageButton
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.activity.result.IntentSenderRequest
|
import androidx.activity.result.IntentSenderRequest
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.annotation.OptIn
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
|
@ -59,17 +59,17 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.VideoSize
|
||||||
|
import androidx.media3.datasource.cronet.CronetDataSource
|
||||||
|
import androidx.media3.exoplayer.DefaultLoadControl
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||||
|
import androidx.media3.ui.AspectRatioFrameLayout
|
||||||
|
import androidx.media3.ui.PlayerView
|
||||||
import androidx.webkit.WebViewCompat
|
import androidx.webkit.WebViewCompat
|
||||||
import androidx.webkit.WebViewFeature
|
import androidx.webkit.WebViewFeature
|
||||||
import com.google.android.exoplayer2.DefaultLoadControl
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.Player
|
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
|
||||||
import com.google.android.exoplayer2.ext.cronet.CronetDataSource
|
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
|
||||||
import com.google.android.exoplayer2.ui.PlayerView
|
|
||||||
import com.google.android.exoplayer2.video.VideoSize
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import eightbitlab.com.blurview.RenderScriptBlur
|
import eightbitlab.com.blurview.RenderScriptBlur
|
||||||
import io.homeassistant.companion.android.BaseActivity
|
import io.homeassistant.companion.android.BaseActivity
|
||||||
|
@ -85,7 +85,6 @@ import io.homeassistant.companion.android.database.authentication.Authentication
|
||||||
import io.homeassistant.companion.android.database.authentication.AuthenticationDao
|
import io.homeassistant.companion.android.database.authentication.AuthenticationDao
|
||||||
import io.homeassistant.companion.android.databinding.ActivityWebviewBinding
|
import io.homeassistant.companion.android.databinding.ActivityWebviewBinding
|
||||||
import io.homeassistant.companion.android.databinding.DialogAuthenticationBinding
|
import io.homeassistant.companion.android.databinding.DialogAuthenticationBinding
|
||||||
import io.homeassistant.companion.android.databinding.ExoPlayerViewBinding
|
|
||||||
import io.homeassistant.companion.android.launch.LaunchActivity
|
import io.homeassistant.companion.android.launch.LaunchActivity
|
||||||
import io.homeassistant.companion.android.matter.MatterFrontendCommissioningStatus
|
import io.homeassistant.companion.android.matter.MatterFrontendCommissioningStatus
|
||||||
import io.homeassistant.companion.android.nfc.WriteNfcTag
|
import io.homeassistant.companion.android.nfc.WriteNfcTag
|
||||||
|
@ -118,6 +117,7 @@ import java.util.concurrent.Executors
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import io.homeassistant.companion.android.common.R as commonR
|
import io.homeassistant.companion.android.common.R as commonR
|
||||||
|
|
||||||
|
@OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webview.WebView {
|
class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webview.WebView {
|
||||||
|
|
||||||
|
@ -196,7 +196,6 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
private lateinit var myCustomView: View
|
private lateinit var myCustomView: View
|
||||||
private lateinit var authenticator: Authenticator
|
private lateinit var authenticator: Authenticator
|
||||||
private lateinit var exoPlayerView: PlayerView
|
private lateinit var exoPlayerView: PlayerView
|
||||||
private lateinit var playerBinding: ExoPlayerViewBinding
|
|
||||||
private lateinit var windowInsetsController: WindowInsetsControllerCompat
|
private lateinit var windowInsetsController: WindowInsetsControllerCompat
|
||||||
|
|
||||||
private var mFilePathCallback: ValueCallback<Array<Uri>>? = null
|
private var mFilePathCallback: ValueCallback<Array<Uri>>? = null
|
||||||
|
@ -208,13 +207,13 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
private var firstAuthTime: Long = 0
|
private var firstAuthTime: Long = 0
|
||||||
private var resourceURL: String = ""
|
private var resourceURL: String = ""
|
||||||
private var appLocked = true
|
private var appLocked = true
|
||||||
private var exoPlayer: SimpleExoPlayer? = null
|
private var exoPlayer: ExoPlayer? = null
|
||||||
private var isExoFullScreen = false
|
private var isExoFullScreen = false
|
||||||
private var exoTop: Int = 0 // These margins are from the DOM and scaled to screen
|
private var exoTop = 0 // These margins are from the DOM and scaled to screen
|
||||||
private var exoLeft: Int = 0
|
private var exoLeft = 0
|
||||||
private var exoRight: Int = 0
|
private var exoRight = 0
|
||||||
private var exoBottom: Int = 0
|
private var exoBottom = 0
|
||||||
private var exoMute: Boolean = true
|
private var exoMute = true
|
||||||
private var failedConnection = "external"
|
private var failedConnection = "external"
|
||||||
private var clearHistory = false
|
private var clearHistory = false
|
||||||
private var moreInfoEntity = ""
|
private var moreInfoEntity = ""
|
||||||
|
@ -253,12 +252,8 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
exoPlayerView.visibility = View.GONE
|
exoPlayerView.visibility = View.GONE
|
||||||
exoPlayerView.setBackgroundColor(Color.BLACK)
|
exoPlayerView.setBackgroundColor(Color.BLACK)
|
||||||
exoPlayerView.alpha = 1f
|
exoPlayerView.alpha = 1f
|
||||||
exoPlayerView.setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
|
|
||||||
exoPlayerView.controllerHideOnTouch = true
|
|
||||||
exoPlayerView.controllerShowTimeoutMs = 2000
|
exoPlayerView.controllerShowTimeoutMs = 2000
|
||||||
|
|
||||||
playerBinding = ExoPlayerViewBinding.bind(exoPlayerView)
|
|
||||||
|
|
||||||
appLocked = presenter.isAppLocked()
|
appLocked = presenter.isAppLocked()
|
||||||
binding.blurView.setBlurEnabled(appLocked)
|
binding.blurView.setBlurEnabled(appLocked)
|
||||||
|
|
||||||
|
@ -852,7 +847,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
val uri = Uri.parse(payload.getString("url"))
|
val uri = Uri.parse(payload.getString("url"))
|
||||||
exoMute = payload.optBoolean("muted")
|
exoMute = payload.optBoolean("muted")
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
exoPlayer = SimpleExoPlayer.Builder(applicationContext).setMediaSourceFactory(
|
exoPlayer = ExoPlayer.Builder(applicationContext).setMediaSourceFactory(
|
||||||
DefaultMediaSourceFactory(
|
DefaultMediaSourceFactory(
|
||||||
CronetDataSource.Factory(
|
CronetDataSource.Factory(
|
||||||
CronetEngine.Builder(applicationContext).enableQuic(true).build(),
|
CronetEngine.Builder(applicationContext).enableQuic(true).build(),
|
||||||
|
@ -872,6 +867,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
exoPlayer?.addListener(object : Player.Listener {
|
exoPlayer?.addListener(object : Player.Listener {
|
||||||
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||||
super.onVideoSizeChanged(videoSize)
|
super.onVideoSizeChanged(videoSize)
|
||||||
|
if (videoSize.height == 0 || videoSize.width == 0) return
|
||||||
exoBottom =
|
exoBottom =
|
||||||
exoTop + ((exoRight - exoLeft) * videoSize.height / videoSize.width)
|
exoTop + ((exoRight - exoLeft) * videoSize.height / videoSize.width)
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
|
@ -880,16 +876,15 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
exoPlayer?.prepare()
|
exoPlayer?.prepare()
|
||||||
exoMute = !exoMute
|
exoMute = !exoMute // Invert because exoToggleMute() will invert again
|
||||||
exoToggleMute()
|
exoToggleMute()
|
||||||
exoPlayerView.player = exoPlayer
|
exoPlayerView.setFullscreenButtonClickListener { isFullScreen ->
|
||||||
exoPlayerView.visibility = View.VISIBLE
|
isExoFullScreen = isFullScreen
|
||||||
|
|
||||||
findViewById<ImageView>(R.id.exo_fullscreen_icon).setOnClickListener {
|
|
||||||
isExoFullScreen = !isExoFullScreen
|
|
||||||
exoResizeLayout()
|
exoResizeLayout()
|
||||||
}
|
}
|
||||||
findViewById<ImageView>(R.id.exo_mute_icon).setOnClickListener { exoToggleMute() }
|
exoPlayerView.player = exoPlayer
|
||||||
|
exoPlayerView.visibility = View.VISIBLE
|
||||||
|
findViewById<ImageButton>(R.id.exo_ha_mute)?.setOnClickListener { exoToggleMute() }
|
||||||
}
|
}
|
||||||
webView.externalBus(
|
webView.externalBus(
|
||||||
id = json.get("id"),
|
id = json.get("id"),
|
||||||
|
@ -932,20 +927,10 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
exoMute = !exoMute
|
exoMute = !exoMute
|
||||||
if (exoMute) {
|
if (exoMute) {
|
||||||
exoPlayer?.volume = 0f
|
exoPlayer?.volume = 0f
|
||||||
findViewById<ImageView>(R.id.exo_mute_icon).setImageDrawable(
|
findViewById<ImageButton>(R.id.exo_ha_mute)?.setImageResource(R.drawable.ic_baseline_volume_off_24)
|
||||||
ContextCompat.getDrawable(
|
|
||||||
applicationContext,
|
|
||||||
R.drawable.ic_baseline_volume_off_24
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
exoPlayer?.volume = 1f
|
exoPlayer?.volume = 1f
|
||||||
findViewById<ImageView>(R.id.exo_mute_icon).setImageDrawable(
|
findViewById<ImageButton>(R.id.exo_ha_mute)?.setImageResource(R.drawable.ic_baseline_volume_up_24)
|
||||||
ContextCompat.getDrawable(
|
|
||||||
applicationContext,
|
|
||||||
R.drawable.ic_baseline_volume_up_24
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,22 +938,16 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
val exoLayoutParams = exoPlayerView.layoutParams as FrameLayout.LayoutParams
|
val exoLayoutParams = exoPlayerView.layoutParams as FrameLayout.LayoutParams
|
||||||
if (isExoFullScreen) {
|
if (isExoFullScreen) {
|
||||||
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
playerBinding.exoContentFrame.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
|
exoPlayerView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||||
} else {
|
} else {
|
||||||
playerBinding.exoContentFrame.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH
|
exoPlayerView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH
|
||||||
}
|
}
|
||||||
exoLayoutParams.setMargins(0, 0, 0, 0)
|
exoLayoutParams.setMargins(0, 0, 0, 0)
|
||||||
exoPlayerView.layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT
|
exoPlayerView.layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
exoPlayerView.layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT
|
exoPlayerView.layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
findViewById<ImageView>(R.id.exo_fullscreen_icon).setImageDrawable(
|
|
||||||
ContextCompat.getDrawable(
|
|
||||||
applicationContext,
|
|
||||||
R.drawable.ic_baseline_fullscreen_exit_24
|
|
||||||
)
|
|
||||||
)
|
|
||||||
hideSystemUI()
|
hideSystemUI()
|
||||||
} else {
|
} else {
|
||||||
playerBinding.exoContentFrame.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
|
exoPlayerView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||||
exoPlayerView.layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT
|
exoPlayerView.layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT
|
||||||
exoPlayerView.layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT
|
exoPlayerView.layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT
|
||||||
val screenWidth: Int = resources.displayMetrics.widthPixels
|
val screenWidth: Int = resources.displayMetrics.widthPixels
|
||||||
|
@ -979,12 +958,6 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
|
||||||
maxOf(screenWidth - exoRight, 0),
|
maxOf(screenWidth - exoRight, 0),
|
||||||
maxOf(screenHeight - exoBottom, 0)
|
maxOf(screenHeight - exoBottom, 0)
|
||||||
)
|
)
|
||||||
findViewById<ImageView>(R.id.exo_fullscreen_icon).setImageDrawable(
|
|
||||||
ContextCompat.getDrawable(
|
|
||||||
applicationContext,
|
|
||||||
R.drawable.ic_baseline_fullscreen_24
|
|
||||||
)
|
|
||||||
)
|
|
||||||
showSystemUI()
|
showSystemUI()
|
||||||
}
|
}
|
||||||
exoPlayerView.requestLayout()
|
exoPlayerView.requestLayout()
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z"/>
|
|
||||||
</vector>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M5,16h3v3h2v-5L5,14v2zM8,8L5,8v2h5L10,5L8,5v3zM14,19h2v-3h3v-2h-5v5zM16,8L16,5h-2v5h5L19,8h-3z"/>
|
|
||||||
</vector>
|
|
|
@ -2,8 +2,7 @@
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24">
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z"/>
|
android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z"/>
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24">
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/>
|
android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/>
|
||||||
|
|
|
@ -20,11 +20,12 @@
|
||||||
android:id="@+id/exoviewGroup"
|
android:id="@+id/exoviewGroup"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
<com.google.android.exoplayer2.ui.PlayerView
|
<androidx.media3.ui.PlayerView
|
||||||
android:id="@+id/exoplayerView"
|
android:id="@+id/exoplayerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
</com.google.android.exoplayer2.ui.PlayerView>
|
app:show_buffering="always">
|
||||||
|
</androidx.media3.ui.PlayerView>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -1,67 +1,136 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<!-- Media3 doesn't allow customizing the default player controls, but you can override the layout
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
file and it will pick up this instead of the library layout. Adjusted from the original layout
|
||||||
android:layout_width="match_parent"
|
https://github.com/androidx/media/blob/a94aa8dbd99fc5ddec6ef25bb4c8ad7b3ca39e6f/libraries/ui/src/main/res/layout/exo_player_control_view.xml
|
||||||
android:layout_height="match_parent">
|
to fit the camera livestream use case / previous (ExoPlayer v2) layout by Home Assistant.
|
||||||
<LinearLayout android:id="@+id/exo_play_pause_button"
|
-->
|
||||||
|
<!-- Copyright 2020 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<View android:id="@id/exo_controls_background"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@color/exo_black_opacity_60"/>
|
||||||
|
|
||||||
|
<FrameLayout android:id="@id/exo_bottom_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="@dimen/exo_styled_bottom_bar_height"
|
||||||
android:gravity="center"
|
android:layout_marginTop="@dimen/exo_styled_bottom_bar_margin_top"
|
||||||
android:orientation="horizontal">
|
android:layout_gravity="bottom"
|
||||||
<ImageButton android:id="@+id/exo_play"
|
android:background="@color/exo_bottom_bar_background"
|
||||||
android:layout_height="24dp" android:layout_width="24dp"
|
android:layoutDirection="ltr">
|
||||||
style="@style/ExoMediaButton.Play"/>
|
|
||||||
<ImageButton android:id="@+id/exo_pause"
|
<LinearLayout android:id="@id/exo_time"
|
||||||
android:layout_height="24dp" android:layout_width="24dp"
|
android:layout_width="wrap_content"
|
||||||
style="@style/ExoMediaButton.Pause"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/exo_styled_bottom_bar_time_padding"
|
||||||
|
android:paddingEnd="@dimen/exo_styled_bottom_bar_time_padding"
|
||||||
|
android:paddingLeft="@dimen/exo_styled_bottom_bar_time_padding"
|
||||||
|
android:paddingRight="@dimen/exo_styled_bottom_bar_time_padding"
|
||||||
|
android:layout_gravity="center_vertical|start"
|
||||||
|
android:layoutDirection="ltr">
|
||||||
|
|
||||||
|
<TextView android:id="@id/exo_position"
|
||||||
|
style="@style/ExoStyledControls.TimeText.Position"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/ExoStyledControls.TimeText.Separator"/>
|
||||||
|
|
||||||
|
<TextView android:id="@id/exo_duration"
|
||||||
|
style="@style/ExoStyledControls.TimeText.Duration"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:id="@id/exo_basic_controls"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:layoutDirection="ltr">
|
||||||
|
|
||||||
|
<!-- HA: removed VR/shuffle/repeat/CC/settings buttons, added mute button -->
|
||||||
|
|
||||||
|
<ImageButton android:id="@+id/exo_ha_mute"
|
||||||
|
style="@style/ExoStyledControls.Button.Bottom.HaMute"/>
|
||||||
|
|
||||||
|
<ImageButton android:id="@id/exo_fullscreen"
|
||||||
|
style="@style/ExoStyledControls.Button.Bottom.FullScreen"/>
|
||||||
|
|
||||||
|
<ImageButton android:id="@id/exo_overflow_show"
|
||||||
|
style="@style/ExoStyledControls.Button.Bottom.OverflowShow"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<HorizontalScrollView android:id="@id/exo_extra_controls_scroll_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<LinearLayout android:id="@id/exo_extra_controls"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layoutDirection="ltr">
|
||||||
|
|
||||||
|
<ImageButton android:id="@id/exo_overflow_hide"
|
||||||
|
style="@style/ExoStyledControls.Button.Bottom.OverflowHide"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<View android:id="@id/exo_progress_placeholder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/exo_styled_progress_layout_height"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginBottom="@dimen/exo_styled_progress_margin_bottom"/>
|
||||||
|
|
||||||
|
<LinearLayout android:id="@id/exo_minimal_controls"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginBottom="@dimen/exo_styled_minimal_controls_margin_bottom"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layoutDirection="ltr">
|
||||||
|
|
||||||
|
<ImageButton android:id="@id/exo_minimal_fullscreen"
|
||||||
|
style="@style/ExoStyledControls.Button.Bottom.FullScreen"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:id="@id/exo_center_controls"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="bottom"
|
android:layout_gravity="center"
|
||||||
android:orientation="horizontal">
|
android:background="@android:color/transparent"
|
||||||
<TextView android:id="@+id/exo_position"
|
android:gravity="center"
|
||||||
android:layout_width="wrap_content"
|
android:padding="@dimen/exo_styled_controls_padding"
|
||||||
android:layout_height="wrap_content"
|
android:clipToPadding="false"
|
||||||
android:textSize="14sp"
|
android:layoutDirection="ltr">
|
||||||
android:textStyle="bold"
|
|
||||||
android:paddingLeft="4dp"
|
<!-- HA: removed prev/rewind -->
|
||||||
android:paddingRight="4dp"
|
|
||||||
android:includeFontPadding="false"
|
<ImageButton android:id="@id/exo_play_pause"
|
||||||
android:textColor="#FFBEBEBE"/>
|
style="@style/ExoStyledControls.Button.Center.PlayPause"/>
|
||||||
<View android:id="@+id/exo_progress_placeholder"
|
|
||||||
android:layout_width="0dp"
|
<!-- HA: removed ffwd/next -->
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_height="24dp"/>
|
|
||||||
<TextView android:id="@+id/exo_duration"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:paddingLeft="4dp"
|
|
||||||
android:paddingRight="4dp"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:textColor="#FFBEBEBE"/>
|
|
||||||
<Space
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="4dp"/>
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/exo_mute_icon"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:src="@drawable/ic_baseline_volume_up_24"/>
|
|
||||||
<Space
|
|
||||||
android:layout_width="16dp"
|
|
||||||
android:layout_height="4dp"/>
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/exo_fullscreen_icon"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:src="@drawable/ic_baseline_fullscreen_24"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</FrameLayout>
|
|
||||||
|
</merge>
|
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="#00000000">
|
|
||||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout android:id="@+id/exo_content_frame"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="center">
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/exo_buffering"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:indeterminate="true"
|
|
||||||
/>
|
|
||||||
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
|
||||||
<com.google.android.exoplayer2.ui.PlayerControlView android:id="@+id/exo_controller"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_width="match_parent">
|
|
||||||
</com.google.android.exoplayer2.ui.PlayerControlView>
|
|
||||||
</FrameLayout>
|
|
|
@ -131,4 +131,9 @@
|
||||||
<item name="android:windowIsFloating">true</item>
|
<item name="android:windowIsFloating">true</item>
|
||||||
<item name="android:backgroundDimEnabled">false</item>
|
<item name="android:backgroundDimEnabled">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="ExoStyledControls.Button.Bottom.HaMute">
|
||||||
|
<item name="android:src">@drawable/ic_baseline_volume_up_24</item>
|
||||||
|
<item name="android:contentDescription">@string/mute_unmute</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -188,11 +188,9 @@ dependencies {
|
||||||
implementation(libs.biometric)
|
implementation(libs.biometric)
|
||||||
implementation(libs.webkit)
|
implementation(libs.webkit)
|
||||||
|
|
||||||
implementation(libs.exoplayer.core)
|
implementation(libs.bundles.media3)
|
||||||
implementation(libs.exoplayer.hls)
|
"fullImplementation"(libs.media3.datasource.cronet)
|
||||||
implementation(libs.exoplayer.ui)
|
"minimalImplementation"(libs.media3.datasource.cronet) {
|
||||||
"fullImplementation"(libs.extension.cronet)
|
|
||||||
"minimalImplementation"(libs.extension.cronet) {
|
|
||||||
exclude(group = "com.google.android.gms", module = "play-services-cronet")
|
exclude(group = "com.google.android.gms", module = "play-services-cronet")
|
||||||
}
|
}
|
||||||
"minimalImplementation"(libs.cronet.embedded)
|
"minimalImplementation"(libs.cronet.embedded)
|
||||||
|
|
|
@ -397,6 +397,7 @@
|
||||||
<string name="message_no_connected_nodes">No connected Wear devices, please make sure Bluetooth is on and your watch is paired.</string>
|
<string name="message_no_connected_nodes">No connected Wear devices, please make sure Bluetooth is on and your watch is paired.</string>
|
||||||
<string name="message_some_installed">The Wear app is installed on some of your Wear devices: (%1$s)\n\nClick the button below to install the app on the other devices.</string>
|
<string name="message_some_installed">The Wear app is installed on some of your Wear devices: (%1$s)\n\nClick the button below to install the app on the other devices.</string>
|
||||||
<string name="missing_command_permission">Please open the Home Assistant app and send the command again in order to grant the proper permissions. You will be taken to a page to either grant the Home Assistant app the permission, or you will need to select Permissions from the details page and then grant the missing permission. For command_bluetooth the name of the permission is Nearby devices. If you are attempting to use command_activity to make a phone call you will also need to grant Phone permissions.</string>
|
<string name="missing_command_permission">Please open the Home Assistant app and send the command again in order to grant the proper permissions. You will be taken to a page to either grant the Home Assistant app the permission, or you will need to select Permissions from the details page and then grant the missing permission. For command_bluetooth the name of the permission is Nearby devices. If you are attempting to use command_activity to make a phone call you will also need to grant Phone permissions.</string>
|
||||||
|
<string name="mute_unmute">Mute/Unmute</string>
|
||||||
<string name="areas">Areas</string>
|
<string name="areas">Areas</string>
|
||||||
<string name="more_entities">More entities</string>
|
<string name="more_entities">More entities</string>
|
||||||
<string name="need_help">Need Help?</string>
|
<string name="need_help">Need Help?</string>
|
||||||
|
|
|
@ -23,7 +23,6 @@ converterJackson = "2.9.0"
|
||||||
coreKtx = "1.10.1"
|
coreKtx = "1.10.1"
|
||||||
cronet-embedded = "113.5672.61"
|
cronet-embedded = "113.5672.61"
|
||||||
emojiJava = "5.1.1"
|
emojiJava = "5.1.1"
|
||||||
exoplayer = "2.19.0"
|
|
||||||
firebase-bom = "32.2.0"
|
firebase-bom = "32.2.0"
|
||||||
firebaseAppdistributionGradle = "4.0.0"
|
firebaseAppdistributionGradle = "4.0.0"
|
||||||
fragment-ktx = "1.6.1"
|
fragment-ktx = "1.6.1"
|
||||||
|
@ -40,6 +39,7 @@ ktlint = "11.5.0"
|
||||||
lifecycle = "2.6.1"
|
lifecycle = "2.6.1"
|
||||||
loggingInterceptor = "4.11.0"
|
loggingInterceptor = "4.11.0"
|
||||||
material = "1.9.0"
|
material = "1.9.0"
|
||||||
|
media3 = "1.1.0"
|
||||||
navigation-compose = "2.6.0"
|
navigation-compose = "2.6.0"
|
||||||
okhttp = "4.11.0"
|
okhttp = "4.11.0"
|
||||||
picasso = "2.8"
|
picasso = "2.8"
|
||||||
|
@ -110,10 +110,6 @@ converter-jackson = { module = "com.squareup.retrofit2:converter-jackson", versi
|
||||||
core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
|
core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
|
||||||
cronet-embedded = { module = "org.chromium.net:cronet-embedded", version.ref = "cronet-embedded" }
|
cronet-embedded = { module = "org.chromium.net:cronet-embedded", version.ref = "cronet-embedded" }
|
||||||
emojiJava = { module = "com.vdurmont:emoji-java", version.ref = "emojiJava" }
|
emojiJava = { module = "com.vdurmont:emoji-java", version.ref = "emojiJava" }
|
||||||
extension-cronet = { module = "com.google.android.exoplayer:extension-cronet", version.ref = "exoplayer" }
|
|
||||||
exoplayer-ui = { module = "com.google.android.exoplayer:exoplayer-ui", version.ref = "exoplayer" }
|
|
||||||
exoplayer-hls = { module = "com.google.android.exoplayer:exoplayer-hls", version.ref = "exoplayer" }
|
|
||||||
exoplayer-core = { module = "com.google.android.exoplayer:exoplayer-core", version.ref = "exoplayer" }
|
|
||||||
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" }
|
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" }
|
||||||
firebase-messaging = { module = "com.google.firebase:firebase-messaging" }
|
firebase-messaging = { module = "com.google.firebase:firebase-messaging" }
|
||||||
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" }
|
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" }
|
||||||
|
@ -134,6 +130,10 @@ logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", ver
|
||||||
navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" }
|
navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" }
|
||||||
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||||
material = { module = "com.google.android.material:material", version.ref = "material" }
|
material = { module = "com.google.android.material:material", version.ref = "material" }
|
||||||
|
media3-datasource-cronet = { module = "androidx.media3:media3-datasource-cronet", version.ref = "media3" }
|
||||||
|
media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" }
|
||||||
|
media3-exoplayer-hls = { module = "androidx.media3:media3-exoplayer-hls", version.ref = "media3" }
|
||||||
|
media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3" }
|
||||||
play-services-threadnetwork = { module = "com.google.android.gms:play-services-threadnetwork", version.ref = "play-services-threadnetwork" }
|
play-services-threadnetwork = { module = "com.google.android.gms:play-services-threadnetwork", version.ref = "play-services-threadnetwork" }
|
||||||
play-services-home = { module = "com.google.android.gms:play-services-home", version.ref = "play-services-home" }
|
play-services-home = { module = "com.google.android.gms:play-services-home", version.ref = "play-services-home" }
|
||||||
play-services-location = { module = "com.google.android.gms:play-services-location", version.ref = "play-services-location" }
|
play-services-location = { module = "com.google.android.gms:play-services-location", version.ref = "play-services-location" }
|
||||||
|
@ -154,3 +154,6 @@ wear-remote-interactions = { module = "androidx.wear:wear-remote-interactions",
|
||||||
wear-tiles-material = { module = "androidx.wear.tiles:tiles-material", version.ref = "wear-tiles" }
|
wear-tiles-material = { module = "androidx.wear.tiles:tiles-material", version.ref = "wear-tiles" }
|
||||||
wear-tiles = { module = "androidx.wear.tiles:tiles", version.ref = "wear-tiles" }
|
wear-tiles = { module = "androidx.wear.tiles:tiles", version.ref = "wear-tiles" }
|
||||||
webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
|
webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
|
||||||
|
|
||||||
|
[bundles]
|
||||||
|
media3 = ["media3-exoplayer", "media3-exoplayer-hls", "media3-ui"]
|
Loading…
Reference in a new issue