mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-21 11:43:41 +08:00
fix: restore Android PiP/fullscreen and remove stale media caching
Fixes #142
This commit is contained in:
@@ -2,18 +2,27 @@ package com.kvideo.tv
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.util.Rational
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebChromeClient.CustomViewCallback
|
||||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.activity.ComponentActivity
|
||||
|
||||
@@ -22,36 +31,33 @@ class MainActivity : ComponentActivity() {
|
||||
companion object {
|
||||
private const val PREFS_NAME = "kvideo_tv_settings"
|
||||
private const val PREF_SERVER_URL = "server_url"
|
||||
private const val TAG = "KVideoMainActivity"
|
||||
}
|
||||
|
||||
private lateinit var webView: WebView
|
||||
private lateinit var setupContainer: View
|
||||
private lateinit var fullscreenContainer: FrameLayout
|
||||
private lateinit var urlInput: EditText
|
||||
private lateinit var statusText: TextView
|
||||
private lateinit var openButton: Button
|
||||
private lateinit var saveButton: Button
|
||||
private lateinit var prefs: android.content.SharedPreferences
|
||||
private var customView: View? = null
|
||||
private var customViewCallback: CustomViewCallback? = null
|
||||
private var wasSetupVisibleBeforeFullscreen = false
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
// Fullscreen immersive mode
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
@Suppress("DEPRECATION")
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
)
|
||||
applyImmersiveMode()
|
||||
|
||||
setContentView(R.layout.activity_main)
|
||||
webView = findViewById(R.id.webview)
|
||||
setupContainer = findViewById(R.id.setup_container)
|
||||
fullscreenContainer = findViewById(R.id.fullscreen_container)
|
||||
urlInput = findViewById(R.id.url_input)
|
||||
statusText = findViewById(R.id.status_text)
|
||||
openButton = findViewById(R.id.open_button)
|
||||
@@ -94,7 +100,41 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
webViewClient = WebViewClient()
|
||||
webChromeClient = WebChromeClient()
|
||||
webChromeClient = object : WebChromeClient() {
|
||||
override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
|
||||
if (view == null || callback == null) {
|
||||
callback?.onCustomViewHidden()
|
||||
return
|
||||
}
|
||||
|
||||
if (customView != null) {
|
||||
callback.onCustomViewHidden()
|
||||
return
|
||||
}
|
||||
|
||||
wasSetupVisibleBeforeFullscreen = isSetupVisible()
|
||||
customView = view
|
||||
customViewCallback = callback
|
||||
|
||||
fullscreenContainer.removeAllViews()
|
||||
fullscreenContainer.addView(
|
||||
view,
|
||||
FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
)
|
||||
fullscreenContainer.visibility = View.VISIBLE
|
||||
webView.visibility = View.GONE
|
||||
setupContainer.visibility = View.GONE
|
||||
applyImmersiveMode()
|
||||
}
|
||||
|
||||
override fun onHideCustomView() {
|
||||
exitCustomFullscreen()
|
||||
}
|
||||
}
|
||||
addJavascriptInterface(AndroidPlayerBridge(), "KVideoAndroid")
|
||||
}
|
||||
|
||||
val configuredUrl = getConfiguredUrl()
|
||||
@@ -107,6 +147,11 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (!isSetupVisible() && keyCode == KeyEvent.KEYCODE_BACK && customView != null) {
|
||||
exitCustomFullscreen()
|
||||
return true
|
||||
}
|
||||
|
||||
if (!isSetupVisible() && (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_SETTINGS)) {
|
||||
showSetup(getString(R.string.status_settings_hint))
|
||||
return true
|
||||
@@ -130,6 +175,11 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
@Deprecated("Use OnBackPressedDispatcher")
|
||||
override fun onBackPressed() {
|
||||
if (customView != null) {
|
||||
exitCustomFullscreen()
|
||||
return
|
||||
}
|
||||
|
||||
if (isSetupVisible()) {
|
||||
@Suppress("DEPRECATION")
|
||||
super.onBackPressed()
|
||||
@@ -143,7 +193,30 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
applyImmersiveMode()
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus) {
|
||||
applyImmersiveMode()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPictureInPictureModeChanged(
|
||||
isInPictureInPictureMode: Boolean,
|
||||
newConfig: Configuration
|
||||
) {
|
||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||
if (!isInPictureInPictureMode) {
|
||||
applyImmersiveMode()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
exitCustomFullscreen()
|
||||
webView.destroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
@@ -229,4 +302,66 @@ class MainActivity : ComponentActivity() {
|
||||
val scheme = uri.scheme?.lowercase()
|
||||
return (scheme == "http" || scheme == "https") && !uri.host.isNullOrBlank()
|
||||
}
|
||||
|
||||
private fun applyImmersiveMode() {
|
||||
@Suppress("DEPRECATION")
|
||||
window.decorView.systemUiVisibility = (
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
)
|
||||
}
|
||||
|
||||
private fun exitCustomFullscreen() {
|
||||
val currentCustomView = customView ?: return
|
||||
fullscreenContainer.removeView(currentCustomView)
|
||||
fullscreenContainer.visibility = View.GONE
|
||||
customView = null
|
||||
webView.visibility = View.VISIBLE
|
||||
if (wasSetupVisibleBeforeFullscreen) {
|
||||
setupContainer.visibility = View.VISIBLE
|
||||
}
|
||||
customViewCallback?.onCustomViewHidden()
|
||||
customViewCallback = null
|
||||
wasSetupVisibleBeforeFullscreen = false
|
||||
applyImmersiveMode()
|
||||
}
|
||||
|
||||
private fun isPictureInPictureSupported(): Boolean {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return false
|
||||
}
|
||||
|
||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||
}
|
||||
|
||||
private inner class AndroidPlayerBridge {
|
||||
@JavascriptInterface
|
||||
fun isPictureInPictureSupported(): Boolean = isPictureInPictureSupported()
|
||||
|
||||
@JavascriptInterface
|
||||
fun enterPictureInPicture(width: Int, height: Int): Boolean {
|
||||
if (!isPictureInPictureSupported()) {
|
||||
return false
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
try {
|
||||
exitCustomFullscreen()
|
||||
val builder = android.app.PictureInPictureParams.Builder()
|
||||
if (width > 0 && height > 0) {
|
||||
builder.setAspectRatio(Rational(width, height))
|
||||
}
|
||||
enterPictureInPictureMode(builder.build())
|
||||
} catch (error: IllegalStateException) {
|
||||
Log.w(TAG, "Failed to enter Picture-in-Picture mode", error)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user