Glimpse: Handle ACTION_REVIEW_SECURE

Change-Id: I572fd755a726299acfbe4860c531c6380bf4edc2
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2dd213a..f5ec9d0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -50,6 +50,7 @@
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <action android:name="android.provider.action.REVIEW" />
+                <action android:name="android.provider.action.REVIEW_SECURE" />
 
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
diff --git a/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt b/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt
index 2ed96de..8d29be6 100644
--- a/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt
+++ b/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt
@@ -5,6 +5,7 @@
 
 package org.lineageos.glimpse
 
+import android.app.KeyguardManager
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
@@ -35,6 +36,9 @@
     // okhttp
     private val httpClient = OkHttpClient()
 
+    // System services
+    private val keyguardManager by lazy { getSystemService(KeyguardManager::class.java) }
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
@@ -43,6 +47,12 @@
         // Setup edge-to-edge
         WindowCompat.setDecorFitsSystemWindows(window, false)
 
+        // We only want to show this activity on top of the keyguard if we're being launched with
+        // the ACTION_REVIEW_SECURE intent and the system is currently locked.
+        if (keyguardManager.isKeyguardLocked && intent.action == MediaStore.ACTION_REVIEW_SECURE) {
+            setShowWhenLocked(true)
+        }
+
         handleIntent(intent)
     }
 
@@ -50,8 +60,8 @@
         ioScope.launch {
             when (intent.action) {
                 Intent.ACTION_VIEW -> handleView(intent)
-                MediaStore.ACTION_REVIEW,
-                MediaStore.ACTION_REVIEW_SECURE -> handleReview(intent)
+                MediaStore.ACTION_REVIEW -> handleReview(intent)
+                MediaStore.ACTION_REVIEW_SECURE -> handleReview(intent, true)
                 else -> runOnUiThread {
                     Toast.makeText(
                         this@ViewActivity,
@@ -68,8 +78,9 @@
      * Handle a [Intent.ACTION_VIEW] intent (view a single media, controls also read-only).
      * Must be executed on [ioScope].
      * @param intent The received intent
+     * @param secure Whether we should show this media in a secure manner
      */
-    private fun handleView(intent: Intent) {
+    private fun handleView(intent: Intent, secure: Boolean = false) {
         val uri = intent.data ?: run {
             runOnUiThread {
                 Toast.makeText(
@@ -114,7 +125,7 @@
                 .beginTransaction()
                 .replace(
                     R.id.navHostFragment, MediaViewerFragment.newInstance(
-                        null, null, MediaUri(uri, uriType, dataType)
+                        null, null, MediaUri(uri, uriType, dataType), secure
                     )
                 )
                 .commit()
@@ -127,20 +138,21 @@
      * If uri parsing from [MediaStore] fails, fallback to [handleView].
      * Must be executed on [ioScope].
      * @param intent The received intent
+     * @param secure Whether we should review this media in a secure manner
      */
-    private fun handleReview(intent: Intent) {
+    private fun handleReview(intent: Intent, secure: Boolean = false) {
         intent.data?.let { getMediaStoreMedia(it) }?.also {
             runOnUiThread {
                 supportFragmentManager
                     .beginTransaction()
                     .replace(
                         R.id.navHostFragment, MediaViewerFragment.newInstance(
-                            it, it.bucketId, null
+                            it, it.bucketId, null, secure
                         )
                     )
                     .commit()
             }
-        } ?: handleView(intent)
+        } ?: handleView(intent, secure)
     }
 
     /**
diff --git a/app/src/main/java/org/lineageos/glimpse/fragments/MediaViewerFragment.kt b/app/src/main/java/org/lineageos/glimpse/fragments/MediaViewerFragment.kt
index 6008da1..d4a474b 100644
--- a/app/src/main/java/org/lineageos/glimpse/fragments/MediaViewerFragment.kt
+++ b/app/src/main/java/org/lineageos/glimpse/fragments/MediaViewerFragment.kt
@@ -117,6 +117,7 @@
     private val media by lazy { arguments?.getParcelable(KEY_MEDIA, Media::class) }
     private val albumId by lazy { arguments?.getInt(KEY_ALBUM_ID, -1).takeUnless { it == -1 } }
     private val mediaUri by lazy { arguments?.getParcelable(KEY_MEDIA_URI, MediaUri::class) }
+    private val secure by lazy { arguments?.getBoolean(KEY_SECURE) == true }
 
     // Contracts
     private val deleteUriContract =
@@ -194,14 +195,6 @@
             this@MediaViewerFragment.mediaViewModel.mediaPosition = position
 
             mediaUri?.also {
-                dateTextView.isVisible = false
-                timeTextView.isVisible = false
-
-                favoriteButton.isVisible = false
-                infoButton.isVisible = false
-                adjustButton.isVisible = false
-                deleteButton.isVisible = false
-
                 if (it.mediaType == MediaType.VIDEO) {
                     with(exoPlayerLazy.value) {
                         setMediaItem(MediaItem.fromUri(it.externalContentUri))
@@ -366,6 +359,18 @@
             }
         }
 
+        // Set UI elements visibility based on initial arguments
+        val shouldShowMediaButtons = mediaUri == null && !secure
+
+        dateTextView.isVisible = shouldShowMediaButtons
+        timeTextView.isVisible = shouldShowMediaButtons
+
+        favoriteButton.isVisible = shouldShowMediaButtons
+        shareButton.isVisible = !secure
+        infoButton.isVisible = shouldShowMediaButtons
+        adjustButton.isVisible = shouldShowMediaButtons
+        deleteButton.isVisible = shouldShowMediaButtons
+
         updateSheetsHeight()
 
         permissionsGatedCallback.runAfterPermissionsCheck()
@@ -460,6 +465,7 @@
         private const val KEY_MEDIA = "media"
         private const val KEY_ALBUM_ID = "album_id"
         private const val KEY_MEDIA_URI = "media_uri"
+        private const val KEY_SECURE = "secure"
 
         private val dateFormatter = SimpleDateFormat.getDateInstance()
         private val timeFormatter = SimpleDateFormat.getTimeInstance()
@@ -472,15 +478,18 @@
          *                will show all medias in the device.
          * @param mediaUri The [MediaUri] to display, setting this will disable any kind of
          *                 interaction to [MediaStore] and UI will be stripped down.
+         * @param secure Whether this should be considered a secure session (no edit, no share, etc)
          */
         fun createBundle(
             media: Media? = null,
             albumId: Int? = media?.bucketId,
             mediaUri: MediaUri? = null,
+            secure: Boolean = false,
         ) = bundleOf(
             KEY_MEDIA to media,
             KEY_ALBUM_ID to albumId,
             KEY_MEDIA_URI to mediaUri,
+            KEY_SECURE to secure,
         )
 
         /**
@@ -494,11 +503,13 @@
             media: Media? = null,
             albumId: Int? = media?.bucketId,
             mediaUri: MediaUri? = null,
+            secure: Boolean = false,
         ) = MediaViewerFragment().apply {
             arguments = createBundle(
                 media,
                 albumId,
                 mediaUri,
+                secure,
             )
         }
     }