From c8d80a51dd44f38d5c20cb9a2abc0fb3cc590030 Mon Sep 17 00:00:00 2001
From: Nicolas Pomepuy <nicolas@videolabs.io>
Date: Tue, 14 May 2024 14:50:26 +0200
Subject: [PATCH] Better handling of metered connection warning

---
 .../videolan/mobile/app/AppSetupDelegate.kt   |  24 +++-
 .../videolan/resources/AppContextProvider.kt  |   4 +
 .../src/org/videolan/vlc/PlaybackService.kt   |  19 ++-
 .../vlc/gui/video/VideoPlayerActivity.kt      | 126 ++++++++++++++----
 .../org/videolan/vlc/media/PlaylistManager.kt |   3 -
 5 files changed, 140 insertions(+), 36 deletions(-)

diff --git a/application/app/src/main/java/org/videolan/mobile/app/AppSetupDelegate.kt b/application/app/src/main/java/org/videolan/mobile/app/AppSetupDelegate.kt
index 38697d50bc..eaabf7a5fc 100644
--- a/application/app/src/main/java/org/videolan/mobile/app/AppSetupDelegate.kt
+++ b/application/app/src/main/java/org/videolan/mobile/app/AppSetupDelegate.kt
@@ -20,11 +20,15 @@
 package org.videolan.mobile.app
 
 import android.annotation.TargetApi
+import android.app.Activity
+import android.app.Application
+import android.app.Application.ActivityLifecycleCallbacks
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.os.Build
+import android.os.Bundle
 import kotlinx.coroutines.DEBUG_PROPERTY_NAME
 import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
 import kotlinx.coroutines.Dispatchers
@@ -56,7 +60,7 @@ import org.videolan.vlc.widget.MiniPlayerAppWidgetProvider
 
 interface AppDelegate {
     val appContextProvider : AppContextProvider
-    fun Context.setupApplication()
+    fun Application.setupApplication()
 }
 
 class AppSetupDelegate : AppDelegate,
@@ -67,7 +71,7 @@ class AppSetupDelegate : AppDelegate,
     override val appContextProvider = AppContextProvider
 
     @TargetApi(Build.VERSION_CODES.O)
-    override fun Context.setupApplication() {
+    override fun Application.setupApplication() {
         appContextProvider.init(this)
         NotificationHelper.createNotificationChannels(this)
 
@@ -92,6 +96,22 @@ class AppSetupDelegate : AppDelegate,
         backgroundInit()
         if (Settings.getInstance(this).getBoolean(KEY_ENABLE_REMOTE_ACCESS, false))
             startRemoteAccess()
+
+        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
+            override fun onActivityResumed(activity: Activity) {
+                AppContextProvider.currentActivity = activity
+            }
+
+            override fun onActivityPaused(activity: Activity) {
+                AppContextProvider.currentActivity = null
+            }
+
+            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
+            override fun onActivityStarted(activity: Activity) {}
+            override fun onActivityStopped(activity: Activity) {}
+            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
+            override fun onActivityDestroyed(activity: Activity) {}
+        })
     }
 
     // init operations executed in background threads
diff --git a/application/resources/src/main/java/org/videolan/resources/AppContextProvider.kt b/application/resources/src/main/java/org/videolan/resources/AppContextProvider.kt
index b294721ac2..076c0ea4ea 100644
--- a/application/resources/src/main/java/org/videolan/resources/AppContextProvider.kt
+++ b/application/resources/src/main/java/org/videolan/resources/AppContextProvider.kt
@@ -24,6 +24,7 @@
 
 package org.videolan.resources
 
+import android.app.Activity
 import android.app.Application
 import android.content.Context
 import android.content.ContextWrapper
@@ -34,6 +35,9 @@ import java.lang.reflect.InvocationTargetException
 object AppContextProvider {
 
     private lateinit var context: Context
+    var currentActivity: Activity? = null
+
+
     // Property to get the new locale only on restart to prevent change the locale partially on runtime
     var locale: String? = ""
         private set
diff --git a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
index 490610f9b1..8288067251 100644
--- a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
+++ b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
@@ -20,6 +20,7 @@
 package org.videolan.vlc
 
 import android.annotation.TargetApi
+import android.app.Activity
 import android.app.KeyguardManager
 import android.app.Notification
 import android.app.NotificationManager
@@ -153,6 +154,7 @@ import org.videolan.vlc.gui.dialogs.VideoTracksDialog
 import org.videolan.vlc.gui.dialogs.adapters.VlcTrack
 import org.videolan.vlc.gui.helpers.AudioUtil
 import org.videolan.vlc.gui.helpers.NotificationHelper
+import org.videolan.vlc.gui.helpers.UiTools
 import org.videolan.vlc.gui.helpers.getBitmapFromDrawable
 import org.videolan.vlc.gui.video.PopupManager
 import org.videolan.vlc.gui.video.VideoPlayerActivity
@@ -766,17 +768,20 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
         }
     }
 
-    fun checkMetered(it: Boolean) {
+    private fun checkMetered(metered: Boolean, activity: Activity? = null) {
+        if (!metered) return
         val meteredAction = (settings.getString("metered_connection", "0") ?: "0").toInt()
-        if (isVideoPlaying) {
-            //delegated to the VideoPlayerActivity
-            return
-        }
-        if (it && meteredAction != 0 && isSchemeStreaming(currentMediaLocation)) {
+        if (meteredAction != 0 && isSchemeStreaming(currentMediaLocation)) {
             if (meteredAction == 1) {
                 stop()
                 Toast.makeText(this, R.string.metered_connection_stopped, Toast.LENGTH_LONG).show()
-            } else Toast.makeText(this, R.string.metered_connection_warning, Toast.LENGTH_LONG).show()
+            } else {
+                AppContextProvider.currentActivity?.let {
+                    UiTools.snacker(it, R.string.metered_connection_warning)
+                } ?: run {
+                    Toast.makeText(this, R.string.metered_connection_warning, Toast.LENGTH_LONG).show()
+                }
+            }
         }
     }
 
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt b/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt
index ff93c607a3..3fb3813f8e 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt
@@ -27,27 +27,50 @@ import android.app.KeyguardManager
 import android.app.PictureInPictureParams
 import android.bluetooth.BluetoothA2dp
 import android.bluetooth.BluetoothHeadset
-import android.content.*
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.SharedPreferences
 import android.content.pm.ActivityInfo
 import android.content.res.Configuration
 import android.graphics.Bitmap
 import android.media.AudioManager
 import android.net.Uri
-import android.os.*
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.os.Parcelable
+import android.os.PowerManager
 import android.text.Editable
 import android.text.TextWatcher
 import android.util.DisplayMetrics
 import android.util.Log
 import android.util.Rational
-import android.view.*
+import android.view.Gravity
+import android.view.KeyEvent
+import android.view.MotionEvent
+import android.view.PixelCopy
+import android.view.Surface
+import android.view.SurfaceView
+import android.view.View
 import android.view.View.OnClickListener
 import android.view.View.OnLongClickListener
+import android.view.WindowManager
 import android.view.animation.Animation
 import android.view.animation.AnimationSet
 import android.view.animation.DecelerateInterpolator
 import android.view.animation.RotateAnimation
-import android.widget.*
+import android.widget.CheckBox
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.SeekBar
 import android.widget.SeekBar.OnSeekBarChangeListener
+import android.widget.TextView
+import android.widget.Toast
 import androidx.activity.OnBackPressedCallback
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AppCompatActivity
@@ -76,9 +99,14 @@ import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
 import androidx.window.layout.FoldingFeature
 import androidx.window.layout.WindowInfoTracker
 import androidx.window.layout.WindowLayoutInfo
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 import org.videolan.libvlc.Dialog
 import org.videolan.libvlc.MediaPlayer
 import org.videolan.libvlc.interfaces.IMedia
@@ -89,13 +117,64 @@ import org.videolan.medialibrary.MLServiceLocator
 import org.videolan.medialibrary.Tools
 import org.videolan.medialibrary.interfaces.Medialibrary
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
-import org.videolan.resources.*
+import org.videolan.resources.AndroidDevices
+import org.videolan.resources.AppContextProvider
+import org.videolan.resources.EXIT_PLAYER
+import org.videolan.resources.MOBILE_MAIN_ACTIVITY
+import org.videolan.resources.PLAYLIST_TYPE_ALL
+import org.videolan.resources.PLAY_DISABLE_HARDWARE
+import org.videolan.resources.PLAY_EXTRA_FROM_START
+import org.videolan.resources.PLAY_EXTRA_ITEM_LOCATION
+import org.videolan.resources.PLAY_EXTRA_ITEM_TITLE
+import org.videolan.resources.PLAY_EXTRA_OPENED_POSITION
+import org.videolan.resources.PLAY_EXTRA_START_TIME
+import org.videolan.resources.PLAY_EXTRA_SUBTITLES_LOCATION
+import org.videolan.resources.PLAY_FROM_SERVICE
+import org.videolan.resources.PLAY_FROM_VIDEOGRID
+import org.videolan.resources.TV_AUDIOPLAYER_ACTIVITY
+import org.videolan.resources.buildPkgString
 import org.videolan.resources.util.parcelable
 import org.videolan.resources.util.parcelableList
-import org.videolan.tools.*
-import org.videolan.vlc.*
+import org.videolan.tools.AUDIO_BOOST
+import org.videolan.tools.AUDIO_PREFERRED_LANGUAGE
+import org.videolan.tools.BRIGHTNESS_VALUE
+import org.videolan.tools.DISPLAY_UNDER_NOTCH
+import org.videolan.tools.ENABLE_BRIGHTNESS_GESTURE
+import org.videolan.tools.ENABLE_DOUBLE_TAP_PLAY
+import org.videolan.tools.ENABLE_DOUBLE_TAP_SEEK
+import org.videolan.tools.ENABLE_SCALE_GESTURE
+import org.videolan.tools.ENABLE_SEEK_BUTTONS
+import org.videolan.tools.ENABLE_SWIPE_SEEK
+import org.videolan.tools.ENABLE_VOLUME_GESTURE
+import org.videolan.tools.KEY_VIDEO_APP_SWITCH
+import org.videolan.tools.KEY_VIDEO_CONFIRM_RESUME
+import org.videolan.tools.LAST_LOCK_ORIENTATION
+import org.videolan.tools.LOCK_USE_SENSOR
+import org.videolan.tools.POPUP_FORCE_LEGACY
+import org.videolan.tools.PREF_TIPS_SHOWN
+import org.videolan.tools.SAVE_BRIGHTNESS
+import org.videolan.tools.SCREENSHOT_MODE
+import org.videolan.tools.SCREEN_ORIENTATION
+import org.videolan.tools.SUBTITLE_PREFERRED_LANGUAGE
+import org.videolan.tools.Settings
+import org.videolan.tools.VIDEO_PAUSED
+import org.videolan.tools.VIDEO_RATIO
+import org.videolan.tools.VIDEO_RESUME_TIME
+import org.videolan.tools.VIDEO_RESUME_URI
+import org.videolan.tools.VIDEO_TRANSITION_SHOW
+import org.videolan.tools.dp
+import org.videolan.tools.getContextWithLocale
+import org.videolan.tools.isStarted
+import org.videolan.tools.isVisible
+import org.videolan.tools.putSingle
+import org.videolan.tools.setGone
+import org.videolan.tools.setInvisible
+import org.videolan.tools.setVisible
 import org.videolan.vlc.BuildConfig
+import org.videolan.vlc.PlaybackService
 import org.videolan.vlc.R
+import org.videolan.vlc.getAllTracks
+import org.videolan.vlc.getSelectedVideoTrack
 import org.videolan.vlc.gui.DialogActivity
 import org.videolan.vlc.gui.audio.EqualizerFragment
 import org.videolan.vlc.gui.audio.PlaylistAdapter
@@ -104,7 +183,11 @@ import org.videolan.vlc.gui.dialogs.PlaybackSpeedDialog
 import org.videolan.vlc.gui.dialogs.RenderersDialog
 import org.videolan.vlc.gui.dialogs.SleepTimerDialog
 import org.videolan.vlc.gui.dialogs.adapters.VlcTrack
-import org.videolan.vlc.gui.helpers.*
+import org.videolan.vlc.gui.helpers.BitmapUtil
+import org.videolan.vlc.gui.helpers.KeycodeListener
+import org.videolan.vlc.gui.helpers.PlayerKeyListenerDelegate
+import org.videolan.vlc.gui.helpers.PlayerOptionsDelegate
+import org.videolan.vlc.gui.helpers.UiTools
 import org.videolan.vlc.gui.helpers.UiTools.isTablet
 import org.videolan.vlc.gui.helpers.UiTools.showPinIfNeeded
 import org.videolan.vlc.gui.helpers.hf.StoragePermissionsDelegate
@@ -115,21 +198,28 @@ import org.videolan.vlc.media.VideoResumeStatus
 import org.videolan.vlc.media.WaitConfirmation
 import org.videolan.vlc.repository.ExternalSubRepository
 import org.videolan.vlc.repository.SlaveRepository
-import org.videolan.vlc.util.*
+import org.videolan.vlc.util.DialogDelegate
 import org.videolan.vlc.util.FileUtils
 import org.videolan.vlc.util.FileUtils.getUri
+import org.videolan.vlc.util.FrameRateManager
+import org.videolan.vlc.util.IDialogManager
+import org.videolan.vlc.util.LocaleUtil
 import org.videolan.vlc.util.LocaleUtil.localeEquivalent
+import org.videolan.vlc.util.Permissions
+import org.videolan.vlc.util.Util
+import org.videolan.vlc.util.hasNotch
+import org.videolan.vlc.util.isTalkbackIsEnabled
 import org.videolan.vlc.viewmodels.BookmarkModel
 import org.videolan.vlc.viewmodels.PlaylistModel
 import java.io.File
-import java.lang.Runnable
 import java.text.SimpleDateFormat
-import java.util.*
+import java.util.Date
 import kotlin.math.roundToInt
 
 
 open class VideoPlayerActivity : AppCompatActivity(), PlaybackService.Callback, PlaylistAdapter.IPlayer, OnClickListener, OnLongClickListener, StoragePermissionsDelegate.CustomActionController, TextWatcher, IDialogManager, KeycodeListener {
 
+    private var warnMetered = false
     var hasPhysicalNotch: Boolean = false
     private var subtitlesExtraPath: String? = null
     private lateinit var startedScope: CoroutineScope
@@ -2309,18 +2399,6 @@ open class VideoPlayerActivity : AppCompatActivity(), PlaybackService.Callback,
 
     open fun onServiceChanged(service: PlaybackService?) {
         if (service != null) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-                NetworkConnectionManager.isMetered.observe(this) {
-                    val meteredAction =(settings.getString("metered_connection", "0") ?: "0").toInt()
-                    if (it && meteredAction != 0 && isSchemeStreaming(service.currentMediaLocation)) {
-                        if (meteredAction == 1) {
-                            stop()
-                            Toast.makeText(this, R.string.metered_connection_stopped, Toast.LENGTH_LONG).show()
-                            finish()
-                        } else UiTools.snacker(this, R.string.metered_connection_warning)
-                    }
-                }
-            }
             this.service = service
             if (savedMediaList != null && service.currentMediaWrapper == null) {
                 service.append(savedMediaList!!, savedMediaIndex)
diff --git a/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt b/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
index f7eb021a6f..5a7609a723 100644
--- a/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
+++ b/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
@@ -268,9 +268,6 @@ class PlaylistManager(val service: PlaybackService) : MediaWrapperList.EventList
             service.showNotification()
         }
         if (settings.getBoolean(KEY_AUDIO_FORCE_SHUFFLE, false) && getCurrentMedia()?.type == MediaWrapper.TYPE_AUDIO && !shuffling && canShuffle()) shuffle()
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            service.checkMetered(NetworkConnectionManager.isMetered.value ?: false)
-        }
     }
 
     @Volatile
-- 
GitLab