[tbb-commits] [Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.0-1] 4 commits: Bug 1871214 - improve share interaction with fullscreen - BP, tor-browser#42656

ma1 (@ma1) git at gitlab.torproject.org
Thu May 9 10:53:23 UTC 2024



ma1 pushed to branch firefox-android-115.2.1-13.0-1 at The Tor Project / Applications / firefox-android


Commits:
d3aa11b9 by hackademix at 2024-05-08T18:01:13+02:00
Bug 1871214 - improve share interaction with fullscreen - BP, tor-browser#42656

- - - - -
43756a25 by Arturo Mejia at 2024-05-08T19:23:07+02:00
Bug 1846306 - Do not throw IllegalStateException when unable to find a session for given prompt request in onContentPermissionRequested

- - - - -
44c271d8 by hackademix at 2024-05-08T19:29:05+02:00
Bug 1871217: Improve permission handling in Fullscreen - BP, tor-browser#42656

- - - - -
f72ebb33 by hackademix at 2024-05-08T20:40:25+02:00
Bug 1892296 - improve webauthn experience - BP, tor-browser#42656

- - - - -


6 changed files:

- android-components/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt
- android-components/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt
- android-components/components/feature/webauthn/src/main/java/mozilla/components/feature/webauthn/WebAuthnFeature.kt
- android-components/components/feature/webauthn/src/test/java/mozilla/components/feature/webauthn/WebAuthnFeatureTest.kt
- fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/share/ShareFragment.kt


Changes:

=====================================
android-components/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt
=====================================
@@ -56,12 +56,14 @@ import mozilla.components.concept.engine.permission.SitePermissions
 import mozilla.components.concept.engine.permission.SitePermissions.Status.ALLOWED
 import mozilla.components.concept.engine.permission.SitePermissions.Status.BLOCKED
 import mozilla.components.concept.engine.permission.SitePermissionsStorage
+import mozilla.components.feature.session.SessionUseCases
 import mozilla.components.feature.sitepermissions.SitePermissionsFeature.DialogConfig
 import mozilla.components.feature.tabs.TabsUseCases.SelectOrAddUseCase
 import mozilla.components.lib.state.ext.flowScoped
 import mozilla.components.support.base.feature.LifecycleAwareFeature
 import mozilla.components.support.base.feature.OnNeedToRequestPermissions
 import mozilla.components.support.base.feature.PermissionsFeature
+import mozilla.components.support.base.log.logger.Logger
 import mozilla.components.support.ktx.android.content.isPermissionGranted
 import mozilla.components.support.ktx.kotlin.getOrigin
 import mozilla.components.support.ktx.kotlin.stripDefaultPort
@@ -72,8 +74,6 @@ import mozilla.components.ui.icons.R as iconsR
 
 internal const val PROMPT_FRAGMENT_TAG = "mozac_feature_sitepermissions_prompt_dialog"
 
-private const val FULL_SCREEN_NOTIFICATION_TAG = "mozac_feature_prompts_full_screen_notification_dialog"
-
 @VisibleForTesting
 internal const val STORAGE_ACCESS_DOCUMENTATION_URL =
     "https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API"
@@ -94,13 +94,15 @@ internal const val STORAGE_ACCESS_DOCUMENTATION_URL =
  * need to be requested. Once the request is completed, [onPermissionsResult] needs to be invoked.
  * @property onShouldShowRequestPermissionRationale a callback that allows the feature to query
  * the ActivityCompat.shouldShowRequestPermissionRationale or the Fragment.shouldShowRequestPermissionRationale values.
+ * @property exitFullscreenUseCase optional the use case in charge of exiting fullscreen
  * @property shouldShowDoNotAskAgainCheckBox optional Visibility for Do not ask again Checkbox
  **/
 
 @Suppress("TooManyFunctions", "LargeClass", "LongParameterList")
 class SitePermissionsFeature(
     private val context: Context,
-    private var sessionId: String? = null,
+    @set:VisibleForTesting
+    internal var sessionId: String? = null,
     private val storage: SitePermissionsStorage = OnDiskSitePermissionsStorage(context),
     var sitePermissionsRules: SitePermissionsRules? = null,
     private val fragmentManager: FragmentManager,
@@ -109,6 +111,7 @@ class SitePermissionsFeature(
     override val onNeedToRequestPermissions: OnNeedToRequestPermissions,
     val onShouldShowRequestPermissionRationale: (permission: String) -> Boolean,
     private val store: BrowserStore,
+    private val exitFullscreenUseCase: SessionUseCases.ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen,
     private val shouldShowDoNotAskAgainCheckBox: Boolean = true,
 ) : LifecycleAwareFeature, PermissionsFeature {
     @VisibleForTesting
@@ -116,6 +119,8 @@ class SitePermissionsFeature(
         SelectOrAddUseCase(store)
     }
 
+    private val logger = Logger("SitePermissionsFeature")
+
     internal val ioCoroutineScope by lazy { coroutineScopeInitializer() }
 
     internal var coroutineScopeInitializer = {
@@ -428,26 +433,29 @@ class SitePermissionsFeature(
             consumePermissionRequest(permissionRequest)
             return null
         }
-
-        val private: Boolean = store.state.findTabOrCustomTabOrSelectedTab(sessionId)?.content?.private
-            ?: throw IllegalStateException("Unable to find session for $sessionId or selected session")
+        val tab = store.state.findTabOrCustomTabOrSelectedTab(sessionId)
+        if (tab == null) {
+            logger.error("Unable to find a tab for $sessionId rejecting the prompt request")
+            permissionRequest.reject()
+            consumePermissionRequest(permissionRequest)
+            return null
+        }
 
         val permissionFromStorage = withContext(coroutineScope.coroutineContext) {
-            storage.findSitePermissionsBy(origin, private = private)
+            storage.findSitePermissionsBy(origin, private = tab.content.private)
         }
-
         val prompt = if (shouldApplyRules(permissionFromStorage)) {
             handleRuledFlow(permissionRequest, origin)
         } else {
             handleNoRuledFlow(permissionFromStorage, permissionRequest, origin)
         }
 
-        val fullScreenNotificationDisplayed =
-            fragmentManager.fragments.any { fragment -> fragment.tag == FULL_SCREEN_NOTIFICATION_TAG }
-
-        return if (fullScreenNotificationDisplayed || prompt == null) {
+        return if (prompt == null) {
             null
         } else {
+            // If we are in fullscreen, then exit to show the permission prompt.
+            // This won't have any effect if we are not in fullscreen.
+            exitFullscreenUseCase.invoke(tab.id)
             prompt.show(fragmentManager, PROMPT_FRAGMENT_TAG)
             prompt
         }


=====================================
android-components/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt
=====================================
@@ -600,6 +600,24 @@ class SitePermissionsFeatureTest {
         verify(sitePermissionFeature).consumePermissionRequest(mockPermissionRequest)
     }
 
+    @Test
+    fun `GIVEN sessionId which does not match a selected or custom tab WHEN onContentPermissionRequested() THEN reject, consumePermissionRequest are called `() {
+        val mockPermissionRequest: PermissionRequest = mock {
+            whenever(permissions).thenReturn(listOf(ContentVideoCamera(id = "permission")))
+        }
+
+        doNothing().`when`(mockPermissionRequest).reject()
+
+        sitePermissionFeature.sessionId = null
+
+        runTestOnMain {
+            sitePermissionFeature.onContentPermissionRequested(mockPermissionRequest, URL)
+        }
+
+        verify(mockPermissionRequest).reject()
+        verify(sitePermissionFeature).consumePermissionRequest(mockPermissionRequest)
+    }
+
     @Test
     fun `GIVEN location permissionRequest and shouldApplyRules is true WHEN onContentPermissionRequested() THEN handleRuledFlow is called`() = runTestOnMain {
         // given


=====================================
android-components/components/feature/webauthn/src/main/java/mozilla/components/feature/webauthn/WebAuthnFeature.kt
=====================================
@@ -20,6 +20,8 @@ import mozilla.components.support.base.log.logger.Logger
 class WebAuthnFeature(
     private val engine: Engine,
     private val activity: Activity,
+    private val exitFullScreen: (String?) -> Unit,
+    private val currentTab: () -> String?,
 ) : LifecycleAwareFeature, ActivityResultHandler, ActivityDelegate {
     private val logger = Logger("WebAuthnFeature")
     private var requestCodeCounter = ACTIVITY_REQUEST_CODE
@@ -53,6 +55,7 @@ class WebAuthnFeature(
 
     override fun startIntentSenderForResult(intent: IntentSender, onResult: (Intent?) -> Unit) {
         logger.info("Received activity delegate request with code: $requestCodeCounter")
+        exitFullScreen(currentTab())
         activity.startIntentSenderForResult(intent, requestCodeCounter, null, 0, 0, 0)
         callbackRef = onResult
     }


=====================================
android-components/components/feature/webauthn/src/test/java/mozilla/components/feature/webauthn/WebAuthnFeatureTest.kt
=====================================
@@ -22,6 +22,8 @@ import org.mockito.Mockito.verify
 class WebAuthnFeatureTest {
     private lateinit var engine: Engine
     private lateinit var activity: Activity
+    private val exitFullScreen: (String?) -> Unit = { _ -> exitFullScreenUseCaseCalled = true }
+    private var exitFullScreenUseCaseCalled = false
 
     @Before
     fun setup() {
@@ -31,7 +33,7 @@ class WebAuthnFeatureTest {
 
     @Test
     fun `feature registers itself on start`() {
-        val feature = WebAuthnFeature(engine, activity)
+        val feature = webAuthnFeature()
 
         feature.start()
 
@@ -40,7 +42,7 @@ class WebAuthnFeatureTest {
 
     @Test
     fun `feature unregisters itself on stop`() {
-        val feature = WebAuthnFeature(engine, activity)
+        val feature = webAuthnFeature()
 
         feature.stop()
 
@@ -49,7 +51,7 @@ class WebAuthnFeatureTest {
 
     @Test
     fun `activity delegate starts intent sender`() {
-        val feature = WebAuthnFeature(engine, activity)
+        val feature = webAuthnFeature()
         val callback: ((Intent?) -> Unit) = { }
         val intentSender: IntentSender = mock()
 
@@ -60,7 +62,7 @@ class WebAuthnFeatureTest {
 
     @Test
     fun `callback is invoked`() {
-        val feature = WebAuthnFeature(engine, activity)
+        val feature = webAuthnFeature()
         var callbackInvoked = false
         val callback: ((Intent?) -> Unit) = { callbackInvoked = true }
         val intentSender: IntentSender = mock()
@@ -77,10 +79,14 @@ class WebAuthnFeatureTest {
 
     @Test
     fun `feature won't process results with the wrong request code`() {
-        val feature = WebAuthnFeature(engine, activity)
+        val feature = webAuthnFeature()
 
         val result = feature.onActivityResult(ACTIVITY_REQUEST_CODE - 5, Intent(), 0)
 
         assertFalse(result)
     }
+
+    private fun webAuthnFeature(): WebAuthnFeature {
+        return WebAuthnFeature(engine, activity, { exitFullScreen("") }) { "" }
+    }
 }


=====================================
fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
=====================================
@@ -830,6 +830,8 @@ abstract class BaseBrowserFragment :
                 feature = WebAuthnFeature(
                     engine = requireComponents.core.engine,
                     activity = requireActivity(),
+                    exitFullScreen = requireComponents.useCases.sessionUseCases.exitFullscreen::invoke,
+                    currentTab = { store.state.selectedTabId },
                 ),
                 owner = this,
                 view = view,


=====================================
fenix/app/src/main/java/org/mozilla/fenix/share/ShareFragment.kt
=====================================
@@ -71,6 +71,7 @@ class ShareFragment : AppCompatDialogFragment() {
         container: ViewGroup?,
         savedInstanceState: Bundle?,
     ): View {
+        requireComponents.useCases.sessionUseCases.exitFullscreen.invoke()
         val binding = FragmentShareBinding.inflate(
             inflater,
             container,



View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/f937a405d764a138f19a3b096505887e324e1028...f72ebb33c99b934dff4c79c864c5a3a392bec20c

-- 
This project does not include diff previews in email notifications.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/f937a405d764a138f19a3b096505887e324e1028...f72ebb33c99b934dff4c79c864c5a3a392bec20c
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tbb-commits/attachments/20240509/29653f95/attachment-0001.htm>


More information about the tbb-commits mailing list