[Android] Check for the PiP permission

Nicolas Pomepuy git at videolan.org
Mon Jun 27 16:33:22 UTC 2022


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Mon Jun 27 14:28:26 2022 +0200| [5733b2a4a08797f9e07b09309e4101db88192d17] | committer: Duncan McNamara

Check for the PiP permission

Fixes #2584
The check is done before launching the PiP playback
and when the setting is changed in the app

> https://code.videolan.org/videolan/vlc-android/commit/5733b2a4a08797f9e07b09309e4101db88192d17
---

 .../resources/src/main/res/values/strings.xml      |  2 ++
 .../vlc/gui/preferences/PreferencesVideo.kt        |  1 +
 .../videolan/vlc/gui/video/VideoPlayerActivity.kt  |  1 +
 .../src/org/videolan/vlc/util/Permissions.kt       | 28 +++++++++++++++++++++-
 4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/application/resources/src/main/res/values/strings.xml b/application/resources/src/main/res/values/strings.xml
index f547f5fa7..f79433314 100644
--- a/application/resources/src/main/res/values/strings.xml
+++ b/application/resources/src/main/res/values/strings.xml
@@ -554,6 +554,8 @@
     <string name="allow_settings_access_brightness_description">VLC needs you to grant this permission to change your brightness mode.</string>
     <string name="allow_draw_overlays_title">Allow VLC player popup over other apps</string>
     <string name="allow_sdraw_overlays_description">VLC needs you to grant this permission display your video in a popup over other applications.</string>
+    <string name="allow_pip">Allow VLC player to launch the Picture in Picture</string>
+    <string name="allow_pip_description">VLC needs you to grant this permission to display your video in Picture in Picture mode.</string>
     <string name="permission_ask_again">Grant permission</string>
     <string name="pick_file">Pick a file</string>
     <string name="permission_not_granted">Permission not granted</string>
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/preferences/PreferencesVideo.kt b/application/vlc-android/src/org/videolan/vlc/gui/preferences/PreferencesVideo.kt
index 126ac1992..4b12e7d94 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/preferences/PreferencesVideo.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/preferences/PreferencesVideo.kt
@@ -61,6 +61,7 @@ class PreferencesVideo : BasePreferenceFragment(), SharedPreferences.OnSharedPre
             }
             POPUP_FORCE_LEGACY -> {
                 if (sharedPreferences.getBoolean(key, false) && !Permissions.canDrawOverlays(requireActivity())) Permissions.checkDrawOverlaysPermission(requireActivity())
+                if (!sharedPreferences.getBoolean(key, false) && !Permissions.isPiPAllowed(requireActivity())) Permissions.checkPiPPermission(requireActivity())
             }
         }
     }
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 8e9bdd820..8b2ebd07d 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
@@ -669,6 +669,7 @@ open class VideoPlayerActivity : AppCompatActivity(), PlaybackService.Callback,
 
         val forceLegacy = Settings.getInstance(this).getBoolean(POPUP_FORCE_LEGACY, false)
         if (AndroidDevices.hasPiP && !forceLegacy) {
+            Permissions.checkPiPPermission(this)
             if (AndroidUtil.isOOrLater)
                 try {
                     val track = service?.playlistManager?.player?.mediaplayer?.currentVideoTrack
diff --git a/application/vlc-android/src/org/videolan/vlc/util/Permissions.kt b/application/vlc-android/src/org/videolan/vlc/util/Permissions.kt
index 768598f00..985aa891d 100644
--- a/application/vlc-android/src/org/videolan/vlc/util/Permissions.kt
+++ b/application/vlc-android/src/org/videolan/vlc/util/Permissions.kt
@@ -26,6 +26,7 @@ package org.videolan.vlc.util
 import android.Manifest
 import android.annotation.TargetApi
 import android.app.Activity
+import android.app.AppOpsManager
 import android.app.Dialog
 import android.content.Context
 import android.content.Intent
@@ -37,7 +38,6 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import androidx.core.content.edit
-import androidx.core.net.toUri
 import androidx.fragment.app.FragmentActivity
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.LifecycleOwner
@@ -50,6 +50,7 @@ import org.videolan.resources.util.isExternalStorageManager
 import org.videolan.tools.Settings
 import org.videolan.tools.isCallable
 import org.videolan.tools.putSingle
+import org.videolan.vlc.BuildConfig
 import org.videolan.vlc.R
 import org.videolan.vlc.gui.helpers.hf.StoragePermissionsDelegate.Companion.askStoragePermission
 import org.videolan.vlc.gui.helpers.hf.WriteExternalDelegate
@@ -65,6 +66,7 @@ object Permissions {
     const val PERMISSION_SYSTEM_RINGTONE = 42
     private const val PERMISSION_SYSTEM_BRIGHTNESS = 43
     private const val PERMISSION_SYSTEM_DRAW_OVRLAYS = 44
+    private const val PERMISSION_PIP = 45
 
     var sAlertDialog: Dialog? = null
 
@@ -77,6 +79,19 @@ object Permissions {
         return !AndroidUtil.isMarshMallowOrLater || android.provider.Settings.canDrawOverlays(context)
     }
 
+    fun isPiPAllowed(context: Context):Boolean {
+            val appOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager?
+            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+                    appOps?.unsafeCheckOpNoThrow(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), BuildConfig.APP_ID) == AppOpsManager.MODE_ALLOWED
+                } else {
+                    appOps?.checkOpNoThrow(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), BuildConfig.APP_ID) == AppOpsManager.MODE_ALLOWED
+                }
+            } else {
+                false
+            }
+    }
+
     @TargetApi(Build.VERSION_CODES.M)
     fun canWriteSettings(context: Context): Boolean {
         return !AndroidUtil.isMarshMallowOrLater || android.provider.Settings.System.canWrite(context)
@@ -129,6 +144,12 @@ object Permissions {
         }
     }
 
+    fun checkPiPPermission(activity: FragmentActivity) {
+        if (!isPiPAllowed(activity)) {
+            showSettingsPermissionDialog(activity, PERMISSION_PIP)
+        }
+    }
+
     fun checkWriteSettingsPermission(activity: FragmentActivity, mode: Int) {
         if (!canWriteSettings(activity)) showSettingsPermissionDialog(activity, mode)
     }
@@ -255,6 +276,11 @@ object Permissions {
                 textId = R.string.allow_sdraw_overlays_description
                 action = android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION
             }
+            PERMISSION_PIP -> {
+                titleId = R.string.allow_pip
+                textId = R.string.allow_pip_description
+                action = "android.settings.PICTURE_IN_PICTURE_SETTINGS"
+            }
         }
         val finalAction = action
         val dialogBuilder = AlertDialog.Builder(activity)



More information about the Android mailing list