diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 81a29817..05675554 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,6 @@
-
diff --git a/app/src/main/java/com/futo/platformplayer/AdvancedOrientationListener.kt b/app/src/main/java/com/futo/platformplayer/AdvancedOrientationListener.kt
index acc0baca..2b0897d5 100644
--- a/app/src/main/java/com/futo/platformplayer/AdvancedOrientationListener.kt
+++ b/app/src/main/java/com/futo/platformplayer/AdvancedOrientationListener.kt
@@ -77,10 +77,14 @@ class AdvancedOrientationListener(private val activity: Activity, private val li
lastStableOrientation = newOrientation
lifecycleScope.launch(Dispatchers.Main) {
- delay(stabilityThresholdTime)
- if (newOrientation == lastStableOrientation) {
- lastOrientation = newOrientation
- onOrientationChanged.emit(newOrientation)
+ try {
+ delay(stabilityThresholdTime)
+ if (newOrientation == lastStableOrientation) {
+ lastOrientation = newOrientation
+ onOrientationChanged.emit(newOrientation)
+ }
+ } catch (e: Throwable) {
+ Logger.i(TAG, "Failed to trigger onOrientationChanged", e)
}
}
}
@@ -111,4 +115,8 @@ class AdvancedOrientationListener(private val activity: Activity, private val li
fun stopListening() {
sensorManager.unregisterListener(sensorListener)
}
+
+ companion object {
+ private val TAG = "AdvancedOrientationListener"
+ }
}
diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt
index eb83e298..4c205620 100644
--- a/app/src/main/java/com/futo/platformplayer/Settings.kt
+++ b/app/src/main/java/com/futo/platformplayer/Settings.kt
@@ -487,7 +487,7 @@ class Settings : FragmentedStorageFileJson() {
class CommentSettings {
@FormField(R.string.default_comment_section, FieldForm.DROPDOWN, -1, 0)
@DropdownFieldOptionsId(R.array.comment_sections)
- var defaultCommentSection: Int = 0;
+ var defaultCommentSection: Int = 1;
@FormField(R.string.bad_reputation_comments_fading, FieldForm.TOGGLE, R.string.bad_reputation_comments_fading_description, 0)
var badReputationCommentsFading: Boolean = true;
diff --git a/app/src/main/java/com/futo/platformplayer/SimpleOrientationListener.kt b/app/src/main/java/com/futo/platformplayer/SimpleOrientationListener.kt
index 24c86095..6d231f9d 100644
--- a/app/src/main/java/com/futo/platformplayer/SimpleOrientationListener.kt
+++ b/app/src/main/java/com/futo/platformplayer/SimpleOrientationListener.kt
@@ -5,6 +5,7 @@ import android.content.pm.ActivityInfo
import android.hardware.SensorManager
import android.view.OrientationEventListener
import com.futo.platformplayer.constructs.Event1
+import com.futo.platformplayer.logging.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@@ -34,10 +35,14 @@ class SimpleOrientationListener(
lastStableOrientation = newOrientation
lifecycleScope.launch(Dispatchers.Main) {
- delay(stabilityThresholdTime)
- if (newOrientation == lastStableOrientation) {
- lastOrientation = newOrientation
- onOrientationChanged.emit(newOrientation)
+ try {
+ delay(stabilityThresholdTime)
+ if (newOrientation == lastStableOrientation) {
+ lastOrientation = newOrientation
+ onOrientationChanged.emit(newOrientation)
+ }
+ } catch (e: Throwable) {
+ Logger.i(TAG, "Failed to trigger onOrientationChanged", e)
}
}
}
@@ -52,4 +57,8 @@ class SimpleOrientationListener(
fun stopListening() {
orientationListener.disable()
}
+
+ companion object {
+ private val TAG = "SimpleOrientationListener"
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/Utility.kt b/app/src/main/java/com/futo/platformplayer/Utility.kt
index 7476c600..6e2dc7b8 100644
--- a/app/src/main/java/com/futo/platformplayer/Utility.kt
+++ b/app/src/main/java/com/futo/platformplayer/Utility.kt
@@ -147,8 +147,6 @@ fun InputStream.copyToOutputStream(inputStreamLength: Long, outputStream: Output
@Suppress("DEPRECATION")
fun Activity.setNavigationBarColorAndIcons() {
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.black);
- if (Settings.instance.playback.allowVideoToGoUnderCutout)
- window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.insetsController?.setSystemBarsAppearance(0, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS);
diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
index 8b5fa562..bd998d38 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
@@ -14,6 +14,7 @@ import android.os.StrictMode.VmPolicy
import android.util.Log
import android.util.TypedValue
import android.view.View
+import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.activity.result.ActivityResult
@@ -112,7 +113,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
private lateinit var _overlayContainer: FrameLayout;
private lateinit var _toastView: ToastView;
- private lateinit var _multicastLock: WifiManager.MulticastLock
//Segment Containers
private lateinit var _fragContainerTopBar: FragmentContainerView;
@@ -247,12 +247,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
}
override fun onCreate(savedInstanceState: Bundle?) {
- Logger.i(TAG, "Acquiring multicast lock")
- val wifiManager = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
- _multicastLock = wifiManager.createMulticastLock("mdnsLock")
- _multicastLock.setReferenceCounted(true)
- _multicastLock.acquire()
-
Logger.i(TAG, "MainActivity Starting");
StateApp.instance.setGlobalContext(this, lifecycleScope);
StateApp.instance.mainAppStarting(this);
@@ -260,7 +254,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setNavigationBarColorAndIcons();
-
+ if (Settings.instance.playback.allowVideoToGoUnderCutout)
+ window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
runBlocking {
StatePlatform.instance.updateAvailableClients(this@MainActivity);
@@ -977,7 +972,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
override fun onDestroy() {
super.onDestroy();
Logger.v(TAG, "onDestroy")
- _multicastLock.release()
StateApp.instance.mainAppDestroyed(this);
}
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt
index bb41c48e..f9c0e280 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt
@@ -2,6 +2,7 @@ package com.futo.platformplayer.fragment.mainactivity.main
import android.content.pm.ActivityInfo
import android.content.res.Configuration
+import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.util.Log
@@ -10,6 +11,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowInsetsController
+import android.view.WindowManager
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope
@@ -426,22 +428,42 @@ class VideoDetailFragment : MainFragment {
onMaximized.clear();
}
-
private fun hideSystemUI() {
- WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
- activity?.window?.insetsController?.let { controller ->
- controller.hide(WindowInsets.Type.statusBars())
- controller.hide(WindowInsets.Type.systemBars())
- controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
+ activity?.window?.insetsController?.let { controller ->
+ controller.hide(WindowInsets.Type.statusBars())
+ controller.hide(WindowInsets.Type.systemBars())
+ controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ }
+ } else {
+ @Suppress("DEPRECATION")
+ activity?.window?.setFlags(
+ WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN
+ )
+ @Suppress("DEPRECATION")
+ activity?.window?.decorView?.systemUiVisibility = (
+ View.SYSTEM_UI_FLAG_FULLSCREEN
+ or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ )
}
}
private fun showSystemUI() {
- WindowCompat.setDecorFitsSystemWindows(requireActivity().window, true)
- activity?.window?.insetsController?.let { controller ->
- controller.show(WindowInsets.Type.statusBars())
- controller.show(WindowInsets.Type.systemBars())
- controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ WindowCompat.setDecorFitsSystemWindows(requireActivity().window, true)
+ activity?.window?.insetsController?.let { controller ->
+ controller.show(WindowInsets.Type.statusBars())
+ controller.show(WindowInsets.Type.systemBars())
+ controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT
+ }
+ } else {
+ @Suppress("DEPRECATION")
+ activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
+ @Suppress("DEPRECATION")
+ activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/mdns/MDNSListener.kt b/app/src/main/java/com/futo/platformplayer/mdns/MDNSListener.kt
index 91e8ee95..70268ec0 100644
--- a/app/src/main/java/com/futo/platformplayer/mdns/MDNSListener.kt
+++ b/app/src/main/java/com/futo/platformplayer/mdns/MDNSListener.kt
@@ -232,7 +232,7 @@ class MDNSListener {
private fun receiveLoop(client: DatagramSocket) {
Logger.i(TAG, "Started receive loop")
- val buffer = ByteArray(1024)
+ val buffer = ByteArray(8972)
val packet = DatagramPacket(buffer, buffer.size)
while (_started) {
try {
diff --git a/app/src/main/java/com/futo/platformplayer/receivers/MediaControlReceiver.kt b/app/src/main/java/com/futo/platformplayer/receivers/MediaControlReceiver.kt
index 61bec334..5540406a 100644
--- a/app/src/main/java/com/futo/platformplayer/receivers/MediaControlReceiver.kt
+++ b/app/src/main/java/com/futo/platformplayer/receivers/MediaControlReceiver.kt
@@ -10,7 +10,6 @@ import com.futo.platformplayer.constructs.Event1
class MediaControlReceiver : BroadcastReceiver() {
-
override fun onReceive(context: Context?, intent: Intent?) {
val act = intent?.getStringExtra(EXTRA_MEDIA_ACTION);
Logger.i(TAG, "Received MediaControl Event $act");
diff --git a/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt b/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt
index e12e24af..180c9ea8 100644
--- a/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt
+++ b/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt
@@ -55,9 +55,15 @@ class MediaPlaybackService : Service() {
private var _notificationChannel: NotificationChannel? = null;
private var _mediaSession: MediaSessionCompat? = null;
private var _hasFocus: Boolean = false;
+ private var _isTransientLoss: Boolean = false;
private var _focusRequest: AudioFocusRequest? = null;
private var _audioFocusLossTime_ms: Long? = null
private var _playbackState = PlaybackStateCompat.STATE_NONE;
+ private var _lastAudioFocusAttempt_ms: Long? = null
+ private val isPlaying get() = _playbackState != PlaybackStateCompat.STATE_PAUSED &&
+ _playbackState != PlaybackStateCompat.STATE_STOPPED &&
+ _playbackState != PlaybackStateCompat.STATE_NONE &&
+ _playbackState != PlaybackStateCompat.STATE_ERROR
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Logger.v(TAG, "onStartCommand");
@@ -159,12 +165,7 @@ class MediaPlaybackService : Service() {
Logger.v(TAG, "closeMediaSession");
stopForeground(STOP_FOREGROUND_REMOVE);
- val focusRequest = _focusRequest;
- if (focusRequest != null) {
- _audioManager?.abandonAudioFocusRequest(focusRequest);
- _focusRequest = null;
- }
- _hasFocus = false;
+ abandonAudioFocus()
val notifManager = _notificationManager;
Logger.i(TAG, "Cancelling playback notification (notifManager: ${notifManager != null})");
@@ -335,29 +336,73 @@ class MediaPlaybackService : Service() {
.setState(state, pos, 1f, SystemClock.elapsedRealtime())
.build());
- if(_focusRequest == null)
- setAudioFocus();
-
_playbackState = state;
+ try {
+ setAudioFocus()
+ } catch (e: Throwable) {
+ Logger.e(TAG, "Failed to set audio focus", e)
+ }
}
//TODO: (TBD) This code probably more fitting inside FutoVideoPlayer, as this service is generally only used for global events
private fun setAudioFocus() {
- Log.i(TAG, "Requested audio focus.");
+ if (!isPlaying) {
+ return
+ }
- val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
- .setAcceptsDelayedFocusGain(true)
- .setOnAudioFocusChangeListener(_audioFocusChangeListener)
- .build()
+ if (_hasFocus || _isTransientLoss) {
+ return;
+ }
- _focusRequest = focusRequest;
- val result = _audioManager?.requestAudioFocus(focusRequest)
+ val now = System.currentTimeMillis()
+ val lastAudioFocusAttempt_ms = _lastAudioFocusAttempt_ms
+ if (lastAudioFocusAttempt_ms == null || now - lastAudioFocusAttempt_ms > 1000) {
+ _lastAudioFocusAttempt_ms = now
+ } else {
+ Log.v(TAG, "Skipped trying to get audio focus because gaining audio focus was recently attempted.");
+ return
+ }
+
+ if (_focusRequest == null) {
+ val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
+ .setAcceptsDelayedFocusGain(true)
+ .setOnAudioFocusChangeListener(_audioFocusChangeListener)
+ .build()
+
+ _focusRequest = focusRequest;
+ Log.i(TAG, "Created audio focus request.");
+ }
+
+ Log.i(TAG, "Requesting audio focus.");
+
+ val result = _audioManager?.requestAudioFocus(_focusRequest!!)
Log.i(TAG, "Audio focus request result $result");
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- //TODO: Handle when not possible to get audio focus
- _hasFocus = true;
+ _hasFocus = true
+ _isTransientLoss = false
Log.i(TAG, "Audio focus received");
+ } else if (result == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+ _hasFocus = false
+ _isTransientLoss = false
+ Log.i(TAG, "Audio focus delayed, waiting for focus")
+ } else {
+ _hasFocus = false
+ _isTransientLoss = false
+ Log.i(TAG, "Audio focus not granted, retrying later")
}
+
+ Log.i(TAG, "Audio focus requested.");
+ }
+
+ private fun abandonAudioFocus() {
+ val focusRequest = _focusRequest;
+ if (focusRequest != null) {
+ Logger.i(TAG, "Audio focus abandoned")
+ _audioManager?.abandonAudioFocusRequest(focusRequest);
+ _focusRequest = null;
+ }
+ _hasFocus = false;
+ _isTransientLoss = false;
}
private val _audioFocusChangeListener =
@@ -365,9 +410,8 @@ class MediaPlaybackService : Service() {
try {
when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
- //Do not start playing on gaining audo focus
- //MediaControlReceiver.onPlayReceived.emit();
_hasFocus = true;
+ _isTransientLoss = false;
Log.i(TAG, "Audio focus gained (restartPlaybackAfterLoss = ${Settings.instance.playback.restartPlaybackAfterLoss}, _audioFocusLossTime_ms = $_audioFocusLossTime_ms)");
if (Settings.instance.playback.restartPlaybackAfterLoss == 1) {
@@ -385,40 +429,28 @@ class MediaPlaybackService : Service() {
}
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
- MediaControlReceiver.onPauseReceived.emit();
- if (_playbackState != PlaybackStateCompat.STATE_PAUSED &&
- _playbackState != PlaybackStateCompat.STATE_STOPPED &&
- _playbackState != PlaybackStateCompat.STATE_NONE &&
- _playbackState != PlaybackStateCompat.STATE_ERROR) {
- _audioFocusLossTime_ms = System.currentTimeMillis()
- }
-
- Log.i(TAG, "Audio focus transient loss");
- }
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
- Log.i(TAG, "Audio focus transient loss, can duck");
- }
- AudioManager.AUDIOFOCUS_LOSS -> {
- if (_playbackState != PlaybackStateCompat.STATE_PAUSED &&
- _playbackState != PlaybackStateCompat.STATE_STOPPED &&
- _playbackState != PlaybackStateCompat.STATE_NONE &&
- _playbackState != PlaybackStateCompat.STATE_ERROR) {
+ if (isPlaying) {
_audioFocusLossTime_ms = System.currentTimeMillis()
}
_hasFocus = false;
+ _isTransientLoss = true;
MediaControlReceiver.onPauseReceived.emit();
- Log.i(TAG, "Audio focus lost");
-
- val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
- val runningAppProcesses = activityManager.runningAppProcesses
- for (processInfo in runningAppProcesses) {
- // Check the importance of the running app process
- if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
- // This app is in the foreground, which might have caused the loss of audio focus
- Log.i("AudioFocus", "App ${processInfo.processName} might have caused the loss of audio focus")
- }
+ Log.i(TAG, "Audio focus transient loss (_audioFocusLossTime_ms = ${_audioFocusLossTime_ms})");
+ }
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
+ Log.i(TAG, "Audio focus transient loss, can duck");
+ _hasFocus = true;
+ _isTransientLoss = true;
+ }
+ AudioManager.AUDIOFOCUS_LOSS -> {
+ if (isPlaying) {
+ _audioFocusLossTime_ms = System.currentTimeMillis()
}
+
+ MediaControlReceiver.onPauseReceived.emit();
+ abandonAudioFocus();
+ Log.i(TAG, "Audio focus lost");
}
}
} catch(ex: Throwable) {
diff --git a/app/src/stable/assets/sources/bilibili b/app/src/stable/assets/sources/bilibili
index 850acb49..31490e10 160000
--- a/app/src/stable/assets/sources/bilibili
+++ b/app/src/stable/assets/sources/bilibili
@@ -1 +1 @@
-Subproject commit 850acb49a8d988f45b893ef848d559dd74d0db1f
+Subproject commit 31490e10f9ef661d6365c0cf4d0fcedf9d807a69
diff --git a/app/src/unstable/assets/sources/bilibili b/app/src/unstable/assets/sources/bilibili
index 850acb49..31490e10 160000
--- a/app/src/unstable/assets/sources/bilibili
+++ b/app/src/unstable/assets/sources/bilibili
@@ -1 +1 @@
-Subproject commit 850acb49a8d988f45b893ef848d559dd74d0db1f
+Subproject commit 31490e10f9ef661d6365c0cf4d0fcedf9d807a69