From 1cf5f776d56bcbc47ac76d52a5f60583cfbafffd Mon Sep 17 00:00:00 2001 From: Koen J Date: Fri, 3 Oct 2025 19:22:46 +0200 Subject: [PATCH 1/3] Trial 1 --- .../platformplayer/RootInsetsController.kt | 118 ++++++++++++++++++ .../platformplayer/activities/MainActivity.kt | 19 ++- app/src/main/res/values/themes.xml | 3 +- 3 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/futo/platformplayer/RootInsetsController.kt diff --git a/app/src/main/java/com/futo/platformplayer/RootInsetsController.kt b/app/src/main/java/com/futo/platformplayer/RootInsetsController.kt new file mode 100644 index 00000000..bf1d45ff --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/RootInsetsController.kt @@ -0,0 +1,118 @@ +package com.futo.platformplayer + +import android.app.Activity +import android.graphics.Color +import android.os.Build +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import androidx.core.graphics.Insets +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsCompat.Type +import androidx.core.view.WindowInsetsControllerCompat +import androidx.core.view.doOnAttach +import androidx.core.view.updatePadding +import kotlin.math.max + +class RootInsetsController private constructor( + private val activity: Activity, + private val window: Window, + private val root: ViewGroup +) { + private val controller by lazy { WindowInsetsControllerCompat(window, root) } + + private val basePaddingLeft = root.paddingLeft + private val basePaddingTop = root.paddingTop + private val basePaddingRight = root.paddingRight + private val basePaddingBottom = root.paddingBottom + + private var currentInsets: WindowInsetsCompat = WindowInsetsCompat.CONSUMED + private var fullscreen = false + + init { + WindowCompat.setDecorFitsSystemWindows(window, false) + window.statusBarColor = Color.TRANSPARENT + window.navigationBarColor = Color.TRANSPARENT + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + + ViewCompat.setOnApplyWindowInsetsListener(root) { _, insets -> + currentInsets = insets + applyPadding() + insets + } + + root.doOnAttach { ViewCompat.requestApplyInsets(root) } + } + + private fun effectiveInsets(): Insets { + if (fullscreen) return Insets.NONE + + val sys = currentInsets.getInsets(Type.systemBars()) + val cut = currentInsets.getInsetsIgnoringVisibility(Type.displayCutout()) + val portrait = activity.resources.configuration.orientation == android.content.res.Configuration.ORIENTATION_PORTRAIT + + val top = if (portrait) max(sys.top, cut.top) else sys.top + return Insets.of(sys.left, top, sys.right, sys.bottom) + } + + + private fun applyPadding() { + val e = effectiveInsets() + root.updatePadding( + left = basePaddingLeft + e.left, + top = basePaddingTop + e.top, + right = basePaddingRight + e.right, + bottom = basePaddingBottom + e.bottom + ) + } + + private fun forceRelayoutAndInsets() { + root.post { + ViewCompat.requestApplyInsets(root) + applyPadding() + root.post { + ViewCompat.requestApplyInsets(root) + applyPadding() + } + } + } + + fun enterFullscreen(allowCutoutShortEdges: Boolean = true) { + fullscreen = true + if (allowCutoutShortEdges) { + window.attributes = window.attributes.apply { + layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + } + } + controller.hide(Type.systemBars()) + forceRelayoutAndInsets() + } + + fun exitFullscreen() { + fullscreen = false + window.attributes = window.attributes.apply { + layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT + } + controller.show(Type.systemBars()) + forceRelayoutAndInsets() + } + + fun onConfigurationChanged() { + forceRelayoutAndInsets() + } + + fun setLightSystemBarAppearance(lightStatus: Boolean, lightNav: Boolean) { + controller.isAppearanceLightStatusBars = lightStatus + controller.isAppearanceLightNavigationBars = lightNav + } + + companion object { + fun attach(activity: Activity, root: ViewGroup): RootInsetsController { + return RootInsetsController(activity, activity.window, root) + } + } +} 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 d824d18c..2d56cb35 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt @@ -16,7 +16,6 @@ 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 @@ -36,6 +35,7 @@ import androidx.lifecycle.withStateAtLeast import androidx.media3.common.util.UnstableApi import com.futo.platformplayer.BuildConfig import com.futo.platformplayer.R +import com.futo.platformplayer.RootInsetsController import com.futo.platformplayer.Settings import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.api.http.ManagedHttpClient @@ -199,6 +199,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { private var _privateModeEnabled = false private var _pictureInPictureEnabled = false private var _isFullscreen = false + private lateinit var _rootInsetsController: RootInsetsController private val _urlQrCodeResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> val scanResult = IntentIntegrator.parseActivityResult(result.resultCode, result.data) @@ -284,9 +285,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { } setContentView(R.layout.activity_main); setNavigationBarColorAndIcons(); - if (Settings.instance.playback.allowVideoToGoUnderCutout) - window.attributes.layoutInDisplayCutoutMode = - WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES runBlocking { try { @@ -301,6 +299,9 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { FragmentedStorage.get(); rootView = findViewById(R.id.rootView); + _rootInsetsController = RootInsetsController.attach(this, rootView) + _rootInsetsController.setLightSystemBarAppearance(lightStatus = false, lightNav = false) + _fragContainerTopBar = findViewById(R.id.fragment_top_bar); _fragContainerMain = findViewById(R.id.fragment_main); _fragContainerBotBar = findViewById(R.id.fragment_bottom_bar); @@ -411,6 +412,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { Logger.i(TAG, "onFullscreenChanged ${it}"); _isFullscreen = it updatePrivateModeVisibility() + if (it) { + _rootInsetsController.enterFullscreen(allowCutoutShortEdges = Settings.instance.playback.allowVideoToGoUnderCutout) + } else { + _rootInsetsController.exitFullscreen() + } } _fragVideoDetail.onMinimize.subscribe { @@ -639,6 +645,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { private var _qrCodeLoadingDialog: AlertDialog? = null + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + _rootInsetsController.onConfigurationChanged() + } + fun showUrlQrCodeScanner() { try { _qrCodeLoadingDialog = UIDialogs.showDialog(this, R.drawable.ic_loader_animated, true, diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 3f2b80c5..2cf3846b 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -42,7 +42,8 @@ @color/gray_30 @color/black - @color/black + @android:color/transparent + @android:color/transparent @style/Theme.FutoVideo.ImageButton @style/Theme.FutoVideo.EditText From 7d8bb20b71563b31bec6f3be181861868339ac94 Mon Sep 17 00:00:00 2001 From: Koen J Date: Mon, 6 Oct 2025 11:00:36 +0200 Subject: [PATCH 2/3] Possible fixes for DownloadService issues. --- .../services/DownloadService.kt | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt b/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt index 8141d191..f75b2500 100644 --- a/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt +++ b/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt @@ -66,10 +66,9 @@ class DownloadService : Service() { return START_NOT_STICKY; if(!FragmentedStorage.isInitialized) { - Logger.i(TAG, "Attempted to start DownloadService without initialized files"); - stopSelf() - closeDownloadSession(); - return START_NOT_STICKY; + Logger.i(TAG, "Attempted to start DownloadService without initialized files") + closeDownloadSession() + return START_NOT_STICKY } _started = true; } @@ -107,12 +106,19 @@ class DownloadService : Service() { return START_STICKY; } fun setupNotificationRequirements() { - _notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager; - _notificationChannel = NotificationChannel(DOWNLOAD_NOTIF_CHANNEL_ID, DOWNLOAD_NOTIF_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT).apply { - this.enableVibration(false); - this.setSound(null, null); - }; - _notificationManager!!.createNotificationChannel(_notificationChannel!!); + _notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + if (_notificationChannel == null) { + _notificationChannel = NotificationChannel( + DOWNLOAD_NOTIF_CHANNEL_ID, + DOWNLOAD_NOTIF_CHANNEL_NAME, + NotificationManager.IMPORTANCE_LOW + ).apply { + enableVibration(false) + setSound(null, null) + setShowBadge(false) + } + } + _notificationManager?.createNotificationChannel(_notificationChannel!!) } override fun onCreate() { @@ -293,21 +299,28 @@ class DownloadService : Service() { val notif = builder.build(); notif.flags = notif.flags or NotificationCompat.FLAG_ONGOING_EVENT or NotificationCompat.FLAG_NO_CLEAR; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - startForeground(DOWNLOAD_NOTIF_ID, notif, FOREGROUND_SERVICE_TYPE_DATA_SYNC); + if (_isForeground) { + _notificationManager?.notify(DOWNLOAD_NOTIF_ID, notif) } else { - startForeground(DOWNLOAD_NOTIF_ID, notif); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + startForeground(DOWNLOAD_NOTIF_ID, notif, FOREGROUND_SERVICE_TYPE_DATA_SYNC) + else + startForeground(DOWNLOAD_NOTIF_ID, notif) + _isForeground = true } } fun closeDownloadSession() { - Logger.i(TAG, "closeDownloadSession"); - stopForeground(STOP_FOREGROUND_REMOVE); - _notificationManager?.cancel(DOWNLOAD_NOTIF_ID); - stopService(); - _started = false; - super.stopSelf(); + Logger.i(TAG, "closeDownloadSession") + if (_isForeground) { + stopForeground(STOP_FOREGROUND_REMOVE) + _isForeground = false + } + _notificationManager?.cancel(DOWNLOAD_NOTIF_ID) + _started = false + super.stopSelf() } + override fun onDestroy() { Logger.i(TAG, "onDestroy"); _instance = null; From 240772790d3b4fb624d90bcb2dfed594e33c11b5 Mon Sep 17 00:00:00 2001 From: Koen J Date: Mon, 6 Oct 2025 11:51:04 +0200 Subject: [PATCH 3/3] Possible fixes for other activities. --- app/src/main/AndroidManifest.xml | 40 +++++++++---------- .../main/res/layout/activity_add_source.xml | 1 - .../layout/activity_add_source_options.xml | 1 - app/src/main/res/layout/activity_dev.xml | 1 - .../main/res/layout/activity_exception.xml | 1 - .../main/res/layout/activity_manage_tabs.xml | 1 - .../res/layout/activity_polycentric_home.xml | 1 - app/src/main/res/layout/activity_settings.xml | 1 - .../res/layout/fragview_article_detail.xml | 1 - .../main/res/layout/fragview_post_detail.xml | 1 - .../main/res/layout/fragview_video_detail.xml | 1 - .../main/res/layout/fragview_web_detail.xml | 1 - app/src/main/res/values-v29/themes.xml | 8 ++++ app/src/main/res/values/themes.xml | 10 +++++ 14 files changed, 38 insertions(+), 31 deletions(-) create mode 100644 app/src/main/res/values-v29/themes.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ea6f3e5b..c5c20aec 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -153,30 +153,30 @@ + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem"> @@ -189,54 +189,54 @@ + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> + android:theme="@style/Theme.FutoVideo.NoActionBarFitsSystem" /> diff --git a/app/src/main/res/layout/activity_add_source.xml b/app/src/main/res/layout/activity_add_source.xml index 469a4508..3b12e6c6 100644 --- a/app/src/main/res/layout/activity_add_source.xml +++ b/app/src/main/res/layout/activity_add_source.xml @@ -15,7 +15,6 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" - android:paddingTop="20dp" android:paddingBottom="15dp"> diff --git a/app/src/main/res/layout/activity_manage_tabs.xml b/app/src/main/res/layout/activity_manage_tabs.xml index 986dfa11..77c8e90c 100644 --- a/app/src/main/res/layout/activity_manage_tabs.xml +++ b/app/src/main/res/layout/activity_manage_tabs.xml @@ -14,7 +14,6 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" - android:paddingTop="20dp" android:paddingBottom="15dp"> diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 0c815387..a29ac552 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -17,7 +17,6 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" - android:paddingTop="20dp" android:paddingBottom="15dp"> diff --git a/app/src/main/res/layout/fragview_post_detail.xml b/app/src/main/res/layout/fragview_post_detail.xml index eb800c5a..0748c17e 100644 --- a/app/src/main/res/layout/fragview_post_detail.xml +++ b/app/src/main/res/layout/fragview_post_detail.xml @@ -5,7 +5,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:fitsSystemWindows="false" android:background="@drawable/bottom_menu_border" android:id="@+id/root" android:clickable="true"> diff --git a/app/src/main/res/layout/fragview_video_detail.xml b/app/src/main/res/layout/fragview_video_detail.xml index 7b8c1dc2..bf287eb9 100644 --- a/app/src/main/res/layout/fragview_video_detail.xml +++ b/app/src/main/res/layout/fragview_video_detail.xml @@ -5,7 +5,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:fitsSystemWindows="false" android:background="@drawable/bottom_menu_border" android:id="@+id/videodetail_root" android:clickable="true"> diff --git a/app/src/main/res/layout/fragview_web_detail.xml b/app/src/main/res/layout/fragview_web_detail.xml index 1bf5d38a..2194126a 100644 --- a/app/src/main/res/layout/fragview_web_detail.xml +++ b/app/src/main/res/layout/fragview_web_detail.xml @@ -5,7 +5,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:fitsSystemWindows="false" android:background="@drawable/bottom_menu_border" android:id="@+id/root" android:clickable="true"> diff --git a/app/src/main/res/values-v29/themes.xml b/app/src/main/res/values-v29/themes.xml new file mode 100644 index 00000000..735f2a4a --- /dev/null +++ b/app/src/main/res/values-v29/themes.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 2cf3846b..fe77ab0b 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -92,6 +92,16 @@ false true true + @color/black + @color/black + @color/black + @color/transparent + false + false + + +