diff --git a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt index 6af815b759c..d7b2d3b3d6d 100644 --- a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt +++ b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt @@ -245,14 +245,19 @@ class GeckoEngineSession( } /** - * See [EngineSession.enableTrackingProtection] + * See [EngineSession.updateTrackingProtection] */ - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) { - val enabled = if (privateMode) { - policy.useForPrivateSessions - } else { - policy.useForRegularSessions + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) { + updateContentBlocking(policy) + val enabled = policy != TrackingProtectionPolicy.none() + etpEnabled = enabled + notifyObservers { + onTrackerBlockingEnabledChange(this, enabled) } + } + + @VisibleForTesting + internal fun updateContentBlocking(policy: TrackingProtectionPolicy) { /** * As described on https://bugzilla.mozilla.org/show_bug.cgi?id=1579264,useTrackingProtection * is a misleading setting. When is set to true is blocking content (scripts/sub-resources). @@ -261,19 +266,20 @@ class GeckoEngineSession( * [TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES]. */ val shouldBlockContent = - policy.contains(TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES) + policy.contains(TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES) - geckoSession.settings.useTrackingProtection = shouldBlockContent && enabled - etpEnabled = enabled - notifyObservers { - onTrackerBlockingEnabledChange(this, enabled) + val enabledInBrowsingMode = if (privateMode) { + policy.useForPrivateSessions + } else { + policy.useForRegularSessions } + geckoSession.settings.useTrackingProtection = enabledInBrowsingMode && shouldBlockContent } // This is a temporary solution to address // https://github.com/mozilla-mobile/android-components/issues/8431 // until we eventually delete [EngineObserver] then this will not be needed. - private var etpEnabled: Boolean? = null + @VisibleForTesting internal var etpEnabled: Boolean? = null override fun register(observer: Observer) { super.register(observer) @@ -292,14 +298,6 @@ class GeckoEngineSession( } } - /** - * See [EngineSession.disableTrackingProtection] - */ - override fun disableTrackingProtection() { - geckoSession.settings.useTrackingProtection = false - notifyObservers { onTrackerBlockingEnabledChange(false) } - } - /** * Indicates if this [EngineSession] should be ignored the tracking protection policies. * @param onResult A callback to inform if this [EngineSession] is in @@ -1052,7 +1050,7 @@ class GeckoEngineSession( private fun createGeckoSession(shouldOpen: Boolean = true) { this.geckoSession = geckoSessionProvider() - defaultSettings?.trackingProtectionPolicy?.let { enableTrackingProtection(it) } + defaultSettings?.trackingProtectionPolicy?.let { updateTrackingProtection(it) } defaultSettings?.requestInterceptor?.let { settings.requestInterceptor = it } defaultSettings?.historyTrackingDelegate?.let { settings.historyTrackingDelegate = it } defaultSettings?.testingModeEnabled?.let { geckoSession.settings.fullAccessibilityTree = it } diff --git a/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt b/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt index 69b5d7ee3d7..4a969d5d80f 100644 --- a/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt +++ b/components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt @@ -1127,85 +1127,125 @@ class GeckoEngineSessionTest { } @Test - fun enableTrackingProtection() { + fun `WHEN updating tracking protection with a recommended policy THEN etpEnabled should be enabled`() { whenever(runtime.settings).thenReturn(mock()) whenever(runtime.settings.contentBlocking).thenReturn(mock()) - val session = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) - val privSession = GeckoEngineSession( - runtime, - geckoSessionProvider = geckoSessionProvider, - privateMode = true - ) + val session = spy(GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider)) var trackerBlockingObserved = false + session.register(object : EngineSession.Observer { override fun onTrackerBlockingEnabledChange(enabled: Boolean) { trackerBlockingObserved = enabled } }) - var privateTrackerBlockingObserved = false - privSession.register(object : EngineSession.Observer { + + val policy = TrackingProtectionPolicy.recommended() + session.updateTrackingProtection(policy) + + verify(session).updateContentBlocking(policy) + assertTrue(session.etpEnabled!!) + assertTrue(trackerBlockingObserved) + } + + @Test + fun `WHEN updating tracking protection with a none policy THEN etpEnabled should be enabled`() { + whenever(runtime.settings).thenReturn(mock()) + whenever(runtime.settings.contentBlocking).thenReturn(mock()) + + val session = spy(GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider)) + var trackerBlockingObserved = false + + session.register(object : EngineSession.Observer { override fun onTrackerBlockingEnabledChange(enabled: Boolean) { - privateTrackerBlockingObserved = enabled + trackerBlockingObserved = enabled } }) - val allPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ) - val regularOnlyPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ).forRegularSessionsOnly() - val privateOnlyPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ).forPrivateSessionsOnly() - - session.enableTrackingProtection(allPolicy) - assertTrue(trackerBlockingObserved) + val policy = TrackingProtectionPolicy.none() + session.updateTrackingProtection(policy) - session.enableTrackingProtection(privateOnlyPolicy) + verify(session).updateContentBlocking(policy) + assertFalse(session.etpEnabled!!) assertFalse(trackerBlockingObserved) - assertEquals( - GeckoCookieBehavior.ACCEPT_ALL, - runtime.settings.contentBlocking.cookieBehavior - ) + } - assertEquals( - ContentBlocking.AntiTracking.NONE, - runtime.settings.contentBlocking.antiTrackingCategories - ) + @Test + fun `WHEN update content blocking with a policy SCRIPTS_AND_SUB_RESOURCES useForPrivateSessions being in privateMode THEN useTrackingProtection should be true`() { + val geckoSetting = mock() + val geckoSession = mock() + + val session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = true + )) - assertFalse(session.geckoSession.settings.useTrackingProtection) + whenever(geckoSession.settings).thenReturn(geckoSetting) - session.enableTrackingProtection(regularOnlyPolicy) - assertTrue(trackerBlockingObserved) + session.geckoSession = geckoSession - privSession.enableTrackingProtection(allPolicy) - assertTrue(privateTrackerBlockingObserved) + val policy = TrackingProtectionPolicy.select(trackingCategories = arrayOf(TrackingCategory.SCRIPTS_AND_SUB_RESOURCES)).forPrivateSessionsOnly() - privSession.enableTrackingProtection(regularOnlyPolicy) - assertFalse(privateTrackerBlockingObserved) + session.updateContentBlocking(policy) - privSession.enableTrackingProtection(privateOnlyPolicy) - assertTrue(privateTrackerBlockingObserved) + verify(geckoSetting).useTrackingProtection = true } @Test - fun disableTrackingProtection() { - whenever(runtime.settings.contentBlocking).thenReturn(mock()) + fun `WHEN calling updateContentBlocking with a policy SCRIPTS_AND_SUB_RESOURCES useForRegularSessions being in privateMode THEN useTrackingProtection should be true`() { + val geckoSetting = mock() + val geckoSession = mock() - val engineSession = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) + val session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = false + )) - var trackerBlockingDisabledObserved = false - engineSession.register(object : EngineSession.Observer { - override fun onTrackerBlockingEnabledChange(enabled: Boolean) { - trackerBlockingDisabledObserved = !enabled - } - }) + whenever(geckoSession.settings).thenReturn(geckoSetting) + + session.geckoSession = geckoSession + + val policy = TrackingProtectionPolicy.select(trackingCategories = arrayOf(TrackingCategory.SCRIPTS_AND_SUB_RESOURCES)).forRegularSessionsOnly() + + session.updateContentBlocking(policy) + + verify(geckoSetting).useTrackingProtection = true + } + + @Test + fun `WHEN updating content blocking without a policy SCRIPTS_AND_SUB_RESOURCES for any browsing mode THEN useTrackingProtection should be false`() { + val geckoSetting = mock() + val geckoSession = mock() + + var session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = false + )) + + whenever(geckoSession.settings).thenReturn(geckoSetting) + session.geckoSession = geckoSession + + val policy = TrackingProtectionPolicy.none() + + session.updateContentBlocking(policy) + + verify(geckoSetting).useTrackingProtection = false + + session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = true + )) + + whenever(geckoSession.settings).thenReturn(geckoSetting) + session.geckoSession = geckoSession + + session.updateContentBlocking(policy) - engineSession.disableTrackingProtection() - assertTrue(trackerBlockingDisabledObserved) - assertFalse(engineSession.geckoSession.settings.useTrackingProtection) + verify(geckoSetting, times(2)).useTrackingProtection = false } @Test @@ -1220,7 +1260,7 @@ class GeckoEngineSessionTest { observers.add(spy(object : EngineSession.Observer {})) } - session.enableTrackingProtection(policy) + session.updateTrackingProtection(policy) observers.forEach { session.register(it) } @@ -1230,7 +1270,7 @@ class GeckoEngineSessionTest { observers.forEach { session.unregister(it) } - session.enableTrackingProtection(policy.forPrivateSessionsOnly()) + session.updateTrackingProtection(TrackingProtectionPolicy.none()) observers.forEach { session.register(it) } diff --git a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt index 6af815b759c..490e9ff6e29 100644 --- a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt +++ b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt @@ -245,14 +245,19 @@ class GeckoEngineSession( } /** - * See [EngineSession.enableTrackingProtection] + * See [EngineSession.updateTrackingProtection] */ - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) { - val enabled = if (privateMode) { - policy.useForPrivateSessions - } else { - policy.useForRegularSessions + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) { + updateContentBlocking(policy) + val enabled = policy != TrackingProtectionPolicy.none() + etpEnabled = enabled + notifyObservers { + onTrackerBlockingEnabledChange(this, enabled) } + } + + @VisibleForTesting + internal fun updateContentBlocking(policy: TrackingProtectionPolicy) { /** * As described on https://bugzilla.mozilla.org/show_bug.cgi?id=1579264,useTrackingProtection * is a misleading setting. When is set to true is blocking content (scripts/sub-resources). @@ -263,17 +268,18 @@ class GeckoEngineSession( val shouldBlockContent = policy.contains(TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES) - geckoSession.settings.useTrackingProtection = shouldBlockContent && enabled - etpEnabled = enabled - notifyObservers { - onTrackerBlockingEnabledChange(this, enabled) + val enabledInBrowsingMode = if (privateMode) { + policy.useForPrivateSessions + } else { + policy.useForRegularSessions } + geckoSession.settings.useTrackingProtection = enabledInBrowsingMode && shouldBlockContent } // This is a temporary solution to address // https://github.com/mozilla-mobile/android-components/issues/8431 // until we eventually delete [EngineObserver] then this will not be needed. - private var etpEnabled: Boolean? = null + @VisibleForTesting internal var etpEnabled: Boolean? = null override fun register(observer: Observer) { super.register(observer) @@ -292,14 +298,6 @@ class GeckoEngineSession( } } - /** - * See [EngineSession.disableTrackingProtection] - */ - override fun disableTrackingProtection() { - geckoSession.settings.useTrackingProtection = false - notifyObservers { onTrackerBlockingEnabledChange(false) } - } - /** * Indicates if this [EngineSession] should be ignored the tracking protection policies. * @param onResult A callback to inform if this [EngineSession] is in @@ -1052,7 +1050,7 @@ class GeckoEngineSession( private fun createGeckoSession(shouldOpen: Boolean = true) { this.geckoSession = geckoSessionProvider() - defaultSettings?.trackingProtectionPolicy?.let { enableTrackingProtection(it) } + defaultSettings?.trackingProtectionPolicy?.let { updateTrackingProtection(it) } defaultSettings?.requestInterceptor?.let { settings.requestInterceptor = it } defaultSettings?.historyTrackingDelegate?.let { settings.historyTrackingDelegate = it } defaultSettings?.testingModeEnabled?.let { geckoSession.settings.fullAccessibilityTree = it } diff --git a/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt b/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt index 69b5d7ee3d7..faab2e9b5ad 100644 --- a/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt +++ b/components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt @@ -1127,89 +1127,129 @@ class GeckoEngineSessionTest { } @Test - fun enableTrackingProtection() { + fun `WHEN updateing tracking protection with a recommended policy THEN etpEnabled should be enabled`() { whenever(runtime.settings).thenReturn(mock()) whenever(runtime.settings.contentBlocking).thenReturn(mock()) - val session = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) - val privSession = GeckoEngineSession( - runtime, - geckoSessionProvider = geckoSessionProvider, - privateMode = true - ) + val session = spy(GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider)) var trackerBlockingObserved = false + session.register(object : EngineSession.Observer { override fun onTrackerBlockingEnabledChange(enabled: Boolean) { trackerBlockingObserved = enabled } }) - var privateTrackerBlockingObserved = false - privSession.register(object : EngineSession.Observer { + + val policy = TrackingProtectionPolicy.recommended() + session.updateTrackingProtection(policy) + + verify(session).updateContentBlocking(policy) + assertTrue(session.etpEnabled!!) + assertTrue(trackerBlockingObserved) + } + + @Test + fun `WHEN calling updateTrackingProtection with a none policy THEN etpEnabled should be disabled`() { + whenever(runtime.settings).thenReturn(mock()) + whenever(runtime.settings.contentBlocking).thenReturn(mock()) + + val session = spy(GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider)) + var trackerBlockingObserved = false + + session.register(object : EngineSession.Observer { override fun onTrackerBlockingEnabledChange(enabled: Boolean) { - privateTrackerBlockingObserved = enabled + trackerBlockingObserved = enabled } }) - val allPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ) - val regularOnlyPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ).forRegularSessionsOnly() - val privateOnlyPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ).forPrivateSessionsOnly() - - session.enableTrackingProtection(allPolicy) - assertTrue(trackerBlockingObserved) + val policy = TrackingProtectionPolicy.none() + session.updateTrackingProtection(policy) - session.enableTrackingProtection(privateOnlyPolicy) + verify(session).updateContentBlocking(policy) + assertFalse(session.etpEnabled!!) assertFalse(trackerBlockingObserved) - assertEquals( - GeckoCookieBehavior.ACCEPT_ALL, - runtime.settings.contentBlocking.cookieBehavior - ) + } - assertEquals( - ContentBlocking.AntiTracking.NONE, - runtime.settings.contentBlocking.antiTrackingCategories - ) + @Test + fun `WHEN updating the contentBlocking with a policy SCRIPTS_AND_SUB_RESOURCES useForPrivateSessions being in privateMode THEN useTrackingProtection should be true`() { + val geckoSetting = mock() + val geckoSession = mock() + + val session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = true + )) - assertFalse(session.geckoSession.settings.useTrackingProtection) + whenever(geckoSession.settings).thenReturn(geckoSetting) - session.enableTrackingProtection(regularOnlyPolicy) - assertTrue(trackerBlockingObserved) + session.geckoSession = geckoSession - privSession.enableTrackingProtection(allPolicy) - assertTrue(privateTrackerBlockingObserved) + val policy = TrackingProtectionPolicy.select(trackingCategories = arrayOf(TrackingCategory.SCRIPTS_AND_SUB_RESOURCES)).forPrivateSessionsOnly() - privSession.enableTrackingProtection(regularOnlyPolicy) - assertFalse(privateTrackerBlockingObserved) + session.updateContentBlocking(policy) - privSession.enableTrackingProtection(privateOnlyPolicy) - assertTrue(privateTrackerBlockingObserved) + verify(geckoSetting).useTrackingProtection = true } @Test - fun disableTrackingProtection() { - whenever(runtime.settings.contentBlocking).thenReturn(mock()) + fun `WHEN calling updateContentBlocking with a policy SCRIPTS_AND_SUB_RESOURCES useForRegularSessions being in privateMode THEN useTrackingProtection should be true`() { + val geckoSetting = mock() + val geckoSession = mock() - val engineSession = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) + val session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = false + )) - var trackerBlockingDisabledObserved = false - engineSession.register(object : EngineSession.Observer { - override fun onTrackerBlockingEnabledChange(enabled: Boolean) { - trackerBlockingDisabledObserved = !enabled - } - }) + whenever(geckoSession.settings).thenReturn(geckoSetting) + + session.geckoSession = geckoSession + + val policy = TrackingProtectionPolicy.select(trackingCategories = arrayOf(TrackingCategory.SCRIPTS_AND_SUB_RESOURCES)).forRegularSessionsOnly() + + session.updateContentBlocking(policy) + + verify(geckoSetting).useTrackingProtection = true + } + + @Test + fun `WHEN updating content blocking without a policy SCRIPTS_AND_SUB_RESOURCES for any browsing mode THEN useTrackingProtection should be false`() { + val geckoSetting = mock() + val geckoSession = mock() + + var session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = false + )) + + whenever(geckoSession.settings).thenReturn(geckoSetting) + session.geckoSession = geckoSession + + val policy = TrackingProtectionPolicy.none() + + session.updateContentBlocking(policy) + + verify(geckoSetting).useTrackingProtection = false + + session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = true + )) + + whenever(geckoSession.settings).thenReturn(geckoSetting) + session.geckoSession = geckoSession + + session.updateContentBlocking(policy) - engineSession.disableTrackingProtection() - assertTrue(trackerBlockingDisabledObserved) - assertFalse(engineSession.geckoSession.settings.useTrackingProtection) + verify(geckoSetting, times(2)).useTrackingProtection = false } @Test - fun `changes to enableTrackingProtection will be notified to all new observers`() { + fun `changes to updateTrackingProtection will be notified to all new observers`() { whenever(runtime.settings).thenReturn(mock()) whenever(runtime.settings.contentBlocking).thenReturn(mock()) val session = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) @@ -1220,7 +1260,7 @@ class GeckoEngineSessionTest { observers.add(spy(object : EngineSession.Observer {})) } - session.enableTrackingProtection(policy) + session.updateTrackingProtection(policy) observers.forEach { session.register(it) } @@ -1230,7 +1270,7 @@ class GeckoEngineSessionTest { observers.forEach { session.unregister(it) } - session.enableTrackingProtection(policy.forPrivateSessionsOnly()) + session.updateTrackingProtection(TrackingProtectionPolicy.none()) observers.forEach { session.register(it) } diff --git a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt index d78ddcb97b1..d928f56a62c 100644 --- a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt +++ b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt @@ -245,14 +245,19 @@ class GeckoEngineSession( } /** - * See [EngineSession.enableTrackingProtection] + * See [EngineSession.updateTrackingProtection] */ - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) { - val enabled = if (privateMode) { - policy.useForPrivateSessions - } else { - policy.useForRegularSessions + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) { + updateContentBlocking(policy) + val enabled = policy != TrackingProtectionPolicy.none() + etpEnabled = enabled + notifyObservers { + onTrackerBlockingEnabledChange(this, enabled) } + } + + @VisibleForTesting + internal fun updateContentBlocking(policy: TrackingProtectionPolicy) { /** * As described on https://bugzilla.mozilla.org/show_bug.cgi?id=1579264,useTrackingProtection * is a misleading setting. When is set to true is blocking content (scripts/sub-resources). @@ -261,19 +266,20 @@ class GeckoEngineSession( * [TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES]. */ val shouldBlockContent = - policy.contains(TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES) + policy.contains(TrackingProtectionPolicy.TrackingCategory.SCRIPTS_AND_SUB_RESOURCES) - geckoSession.settings.useTrackingProtection = shouldBlockContent && enabled - etpEnabled = enabled - notifyObservers { - onTrackerBlockingEnabledChange(this, enabled) + val enabledInBrowsingMode = if (privateMode) { + policy.useForPrivateSessions + } else { + policy.useForRegularSessions } + geckoSession.settings.useTrackingProtection = enabledInBrowsingMode && shouldBlockContent } // This is a temporary solution to address // https://github.com/mozilla-mobile/android-components/issues/8431 // until we eventually delete [EngineObserver] then this will not be needed. - private var etpEnabled: Boolean? = null + @VisibleForTesting internal var etpEnabled: Boolean? = null override fun register(observer: Observer) { super.register(observer) @@ -292,14 +298,6 @@ class GeckoEngineSession( } } - /** - * See [EngineSession.disableTrackingProtection] - */ - override fun disableTrackingProtection() { - geckoSession.settings.useTrackingProtection = false - notifyObservers { onTrackerBlockingEnabledChange(false) } - } - /** * Indicates if this [EngineSession] should be ignored the tracking protection policies. * @param onResult A callback to inform if this [EngineSession] is in @@ -1052,7 +1050,7 @@ class GeckoEngineSession( private fun createGeckoSession(shouldOpen: Boolean = true) { this.geckoSession = geckoSessionProvider() - defaultSettings?.trackingProtectionPolicy?.let { enableTrackingProtection(it) } + defaultSettings?.trackingProtectionPolicy?.let { updateTrackingProtection(it) } defaultSettings?.requestInterceptor?.let { settings.requestInterceptor = it } defaultSettings?.historyTrackingDelegate?.let { settings.historyTrackingDelegate = it } defaultSettings?.testingModeEnabled?.let { geckoSession.settings.fullAccessibilityTree = it } diff --git a/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt b/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt index 69b5d7ee3d7..689883cf7f1 100644 --- a/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt +++ b/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt @@ -1127,85 +1127,125 @@ class GeckoEngineSessionTest { } @Test - fun enableTrackingProtection() { + fun `WHEN updating tracking protection with a recommended policy THEN etpEnabled should be enabled`() { whenever(runtime.settings).thenReturn(mock()) whenever(runtime.settings.contentBlocking).thenReturn(mock()) - val session = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) - val privSession = GeckoEngineSession( - runtime, - geckoSessionProvider = geckoSessionProvider, - privateMode = true - ) + val session = spy(GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider)) var trackerBlockingObserved = false + session.register(object : EngineSession.Observer { override fun onTrackerBlockingEnabledChange(enabled: Boolean) { trackerBlockingObserved = enabled } }) - var privateTrackerBlockingObserved = false - privSession.register(object : EngineSession.Observer { + + val policy = TrackingProtectionPolicy.recommended() + session.updateTrackingProtection(policy) + + verify(session).updateContentBlocking(policy) + assertTrue(session.etpEnabled!!) + assertTrue(trackerBlockingObserved) + } + + @Test + fun `WHEN updating tracking protection with a none policy THEN etpEnabled should be enabled`() { + whenever(runtime.settings).thenReturn(mock()) + whenever(runtime.settings.contentBlocking).thenReturn(mock()) + + val session = spy(GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider)) + var trackerBlockingObserved = false + + session.register(object : EngineSession.Observer { override fun onTrackerBlockingEnabledChange(enabled: Boolean) { - privateTrackerBlockingObserved = enabled + trackerBlockingObserved = enabled } }) - val allPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ) - val regularOnlyPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ).forRegularSessionsOnly() - val privateOnlyPolicy = TrackingProtectionPolicy.select( - trackingCategories = arrayOf(TrackingCategory.AD) - ).forPrivateSessionsOnly() - - session.enableTrackingProtection(allPolicy) - assertTrue(trackerBlockingObserved) + val policy = TrackingProtectionPolicy.none() + session.updateTrackingProtection(policy) - session.enableTrackingProtection(privateOnlyPolicy) + verify(session).updateContentBlocking(policy) + assertFalse(session.etpEnabled!!) assertFalse(trackerBlockingObserved) - assertEquals( - GeckoCookieBehavior.ACCEPT_ALL, - runtime.settings.contentBlocking.cookieBehavior - ) + } - assertEquals( - ContentBlocking.AntiTracking.NONE, - runtime.settings.contentBlocking.antiTrackingCategories - ) + @Test + fun `WHEN updating content blocking with a policy SCRIPTS_AND_SUB_RESOURCES useForPrivateSessions being in privateMode THEN useTrackingProtection should be true`() { + val geckoSetting = mock() + val geckoSession = mock() + + val session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = true + )) - assertFalse(session.geckoSession.settings.useTrackingProtection) + whenever(geckoSession.settings).thenReturn(geckoSetting) - session.enableTrackingProtection(regularOnlyPolicy) - assertTrue(trackerBlockingObserved) + session.geckoSession = geckoSession - privSession.enableTrackingProtection(allPolicy) - assertTrue(privateTrackerBlockingObserved) + val policy = TrackingProtectionPolicy.select(trackingCategories = arrayOf(TrackingCategory.SCRIPTS_AND_SUB_RESOURCES)).forPrivateSessionsOnly() - privSession.enableTrackingProtection(regularOnlyPolicy) - assertFalse(privateTrackerBlockingObserved) + session.updateContentBlocking(policy) - privSession.enableTrackingProtection(privateOnlyPolicy) - assertTrue(privateTrackerBlockingObserved) + verify(geckoSetting).useTrackingProtection = true } @Test - fun disableTrackingProtection() { - whenever(runtime.settings.contentBlocking).thenReturn(mock()) + fun `WHEN calling updateContentBlocking with a policy SCRIPTS_AND_SUB_RESOURCES useForRegularSessions being in privateMode THEN useTrackingProtection should be true`() { + val geckoSetting = mock() + val geckoSession = mock() - val engineSession = GeckoEngineSession(runtime, geckoSessionProvider = geckoSessionProvider) + val session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = false + )) - var trackerBlockingDisabledObserved = false - engineSession.register(object : EngineSession.Observer { - override fun onTrackerBlockingEnabledChange(enabled: Boolean) { - trackerBlockingDisabledObserved = !enabled - } - }) + whenever(geckoSession.settings).thenReturn(geckoSetting) + + session.geckoSession = geckoSession + + val policy = TrackingProtectionPolicy.select(trackingCategories = arrayOf(TrackingCategory.SCRIPTS_AND_SUB_RESOURCES)).forRegularSessionsOnly() + + session.updateContentBlocking(policy) + + verify(geckoSetting).useTrackingProtection = true + } + + @Test + fun `WHEN updating content blocking without a policy SCRIPTS_AND_SUB_RESOURCES for any browsing mode THEN useTrackingProtection should be false`() { + val geckoSetting = mock() + val geckoSession = mock() + + var session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = false + )) + + whenever(geckoSession.settings).thenReturn(geckoSetting) + session.geckoSession = geckoSession + + val policy = TrackingProtectionPolicy.none() + + session.updateContentBlocking(policy) + + verify(geckoSetting).useTrackingProtection = false + + session = spy(GeckoEngineSession( + runtime = runtime, + geckoSessionProvider = geckoSessionProvider, + privateMode = true + )) + + whenever(geckoSession.settings).thenReturn(geckoSetting) + session.geckoSession = geckoSession + + session.updateContentBlocking(policy) - engineSession.disableTrackingProtection() - assertTrue(trackerBlockingDisabledObserved) - assertFalse(engineSession.geckoSession.settings.useTrackingProtection) + verify(geckoSetting, times(2)).useTrackingProtection = false } @Test @@ -1220,7 +1260,7 @@ class GeckoEngineSessionTest { observers.add(spy(object : EngineSession.Observer {})) } - session.enableTrackingProtection(policy) + session.updateTrackingProtection(policy) observers.forEach { session.register(it) } @@ -1230,7 +1270,7 @@ class GeckoEngineSessionTest { observers.forEach { session.unregister(it) } - session.enableTrackingProtection(policy.forPrivateSessionsOnly()) + session.updateTrackingProtection(TrackingProtectionPolicy.none()) observers.forEach { session.register(it) } diff --git a/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineSession.kt b/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineSession.kt index 86ad2beeb00..36d89c958c7 100644 --- a/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineSession.kt +++ b/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineSession.kt @@ -144,9 +144,9 @@ class SystemEngineSession( } /** - * See [EngineSession.enableTrackingProtection] + * See [EngineSession.updateTrackingProtection] */ - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) { + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) { // Make sure Url matcher is preloaded now that tracking protection is enabled CoroutineScope(Dispatchers.IO).launch { SystemEngineView.getOrCreateUrlMatcher(resources, policy) @@ -159,10 +159,8 @@ class SystemEngineSession( notifyObservers { onTrackerBlockingEnabledChange(true) } } - /** - * See [EngineSession.disableTrackingProtection] - */ - override fun disableTrackingProtection() { + @VisibleForTesting + internal fun disableTrackingProtection() { trackingProtectionPolicy = null notifyObservers { onTrackerBlockingEnabledChange(false) } } @@ -331,7 +329,7 @@ class SystemEngineSession( override var trackingProtectionPolicy: TrackingProtectionPolicy? get() = this@SystemEngineSession.trackingProtectionPolicy - set(value) = value?.let { enableTrackingProtection(it) } ?: disableTrackingProtection() + set(value) = value?.let { updateTrackingProtection(it) } ?: disableTrackingProtection() override var historyTrackingDelegate: HistoryTrackingDelegate? get() = this@SystemEngineSession.historyTrackingDelegate diff --git a/components/browser/engine-system/src/test/java/mozilla/components/browser/engine/system/SystemEngineSessionTest.kt b/components/browser/engine-system/src/test/java/mozilla/components/browser/engine/system/SystemEngineSessionTest.kt index a0d163dadfc..c3ab96ba522 100644 --- a/components/browser/engine-system/src/test/java/mozilla/components/browser/engine/system/SystemEngineSessionTest.kt +++ b/components/browser/engine-system/src/test/java/mozilla/components/browser/engine/system/SystemEngineSessionTest.kt @@ -250,7 +250,7 @@ class SystemEngineSessionTest { }) assertNull(engineSession.trackingProtectionPolicy) - runBlocking { engineSession.enableTrackingProtection() } + runBlocking { engineSession.updateTrackingProtection() } assertEquals( EngineSession.TrackingProtectionPolicy.strict(), engineSession.trackingProtectionPolicy @@ -366,7 +366,7 @@ class SystemEngineSessionTest { assertNull(engineSession.settings.trackingProtectionPolicy) engineSession.settings.trackingProtectionPolicy = EngineSession.TrackingProtectionPolicy.strict() - verify(engineSession).enableTrackingProtection(EngineSession.TrackingProtectionPolicy.strict()) + verify(engineSession).updateTrackingProtection(EngineSession.TrackingProtectionPolicy.strict()) engineSession.settings.trackingProtectionPolicy = null verify(engineSession).disableTrackingProtection() @@ -413,7 +413,7 @@ class SystemEngineSessionTest { verify(webViewSettings).loadWithOverviewMode = true verify(webViewSettings).useWideViewPort = true verify(webViewSettings).setSupportMultipleWindows(true) - verify(engineSession).enableTrackingProtection(EngineSession.TrackingProtectionPolicy.strict()) + verify(engineSession).updateTrackingProtection(EngineSession.TrackingProtectionPolicy.strict()) assertFalse(engineSession.webFontsEnabled) } diff --git a/components/browser/session/src/test/java/mozilla/components/browser/session/engine/EngineObserverTest.kt b/components/browser/session/src/test/java/mozilla/components/browser/session/engine/EngineObserverTest.kt index 9b69b8d95e8..073e1a8c5b5 100644 --- a/components/browser/session/src/test/java/mozilla/components/browser/session/engine/EngineObserverTest.kt +++ b/components/browser/session/src/test/java/mozilla/components/browser/session/engine/EngineObserverTest.kt @@ -67,8 +67,7 @@ class EngineObserverTest { override fun reload(flags: LoadUrlFlags) {} override fun stopLoading() {} override fun restoreState(state: EngineSessionState): Boolean { return false } - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) {} - override fun disableTrackingProtection() {} + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) {} override fun toggleDesktopMode(enable: Boolean, reload: Boolean) { notifyObservers { onDesktopModeChange(enable) } } @@ -119,8 +118,7 @@ class EngineObserverTest { override fun stopLoading() {} override fun reload(flags: LoadUrlFlags) {} override fun restoreState(state: EngineSessionState): Boolean { return false } - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) {} - override fun disableTrackingProtection() {} + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) {} override fun toggleDesktopMode(enable: Boolean, reload: Boolean) {} override fun findAll(text: String) {} override fun findNext(forward: Boolean) {} @@ -163,12 +161,7 @@ class EngineObserverTest { override fun stopLoading() {} override fun reload(flags: LoadUrlFlags) {} override fun restoreState(state: EngineSessionState): Boolean { return false } - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) { - notifyObservers { onTrackerBlockingEnabledChange(true) } - } - override fun disableTrackingProtection() { - notifyObservers { onTrackerBlockingEnabledChange(false) } - } + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) {} override fun toggleDesktopMode(enable: Boolean, reload: Boolean) {} override fun loadUrl( url: String, @@ -186,12 +179,6 @@ class EngineObserverTest { val observer = EngineObserver(session, mock()) engineSession.register(observer) - engineSession.enableTrackingProtection() - assertTrue(session.trackerBlockingEnabled) - - engineSession.disableTrackingProtection() - assertFalse(session.trackerBlockingEnabled) - val tracker1 = Tracker("tracker1", emptyList()) val tracker2 = Tracker("tracker2", emptyList()) @@ -1112,4 +1099,45 @@ class EngineObserverTest { ) ) } + + @Test + fun `equality between tracking protection policies`() { + val strict = EngineSession.TrackingProtectionPolicy.strict() + val recommended = EngineSession.TrackingProtectionPolicy.recommended() + val none = EngineSession.TrackingProtectionPolicy.none() + val custom = EngineSession.TrackingProtectionPolicy.select( + trackingCategories = emptyArray(), + cookiePolicy = EngineSession.TrackingProtectionPolicy.CookiePolicy.ACCEPT_ONLY_FIRST_PARTY, + cookiePurging = true, + strictSocialTrackingProtection = true + ) + val custom2 = EngineSession.TrackingProtectionPolicy.select( + trackingCategories = emptyArray(), + cookiePolicy = EngineSession.TrackingProtectionPolicy.CookiePolicy.ACCEPT_ONLY_FIRST_PARTY, + cookiePurging = true, + strictSocialTrackingProtection = true + ) + + val customNone = EngineSession.TrackingProtectionPolicy.select( + trackingCategories = none.trackingCategories, + cookiePolicy = none.cookiePolicy, + cookiePurging = none.cookiePurging, + strictSocialTrackingProtection = false + ) + + assertTrue(strict == EngineSession.TrackingProtectionPolicy.strict()) + assertTrue(recommended == EngineSession.TrackingProtectionPolicy.recommended()) + assertTrue(none == EngineSession.TrackingProtectionPolicy.none()) + assertTrue(custom == custom2) + + assertFalse(strict == EngineSession.TrackingProtectionPolicy.strict().forPrivateSessionsOnly()) + assertFalse(recommended == EngineSession.TrackingProtectionPolicy.recommended().forPrivateSessionsOnly()) + assertFalse(custom == custom2.forPrivateSessionsOnly()) + + assertFalse(strict == EngineSession.TrackingProtectionPolicy.strict().forRegularSessionsOnly()) + assertFalse(recommended == EngineSession.TrackingProtectionPolicy.recommended().forRegularSessionsOnly()) + assertFalse(custom == custom2.forRegularSessionsOnly()) + + assertFalse(none == customNone) + } } diff --git a/components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt b/components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt index a7ee4fe06a6..ee687a57a7c 100644 --- a/components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt +++ b/components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt @@ -7,7 +7,6 @@ package mozilla.components.concept.engine import android.content.Intent import android.graphics.Bitmap import androidx.annotation.CallSuper -import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.Companion.RECOMMENDED import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.CookiePolicy.ACCEPT_ALL import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy.CookiePolicy.ACCEPT_NON_TRACKERS import mozilla.components.concept.engine.content.blocking.Tracker @@ -375,9 +374,6 @@ abstract class EngineSession( } companion object { - - internal val RECOMMENDED = TrackingProtectionPolicy() - fun none() = TrackingProtectionPolicy( trackingCategories = arrayOf(TrackingCategory.NONE), cookiePolicy = ACCEPT_ALL @@ -438,6 +434,8 @@ abstract class EngineSession( if (hashCode() != other.hashCode()) return false if (useForPrivateSessions != other.useForPrivateSessions) return false if (useForRegularSessions != other.useForRegularSessions) return false + if (cookiePurging != other.cookiePurging) return false + if (strictSocialTrackingProtection != other.strictSocialTrackingProtection) return false return true } @@ -606,16 +604,12 @@ abstract class EngineSession( abstract fun restoreState(state: EngineSessionState): Boolean /** - * Enables tracking protection for this engine session. + * Updates the tracking protection [policy] for this engine session. + * If you want to disable tracking protection use [TrackingProtectionPolicy.none]. * * @param policy the tracking protection policy to use, defaults to blocking all trackers. */ - abstract fun enableTrackingProtection(policy: TrackingProtectionPolicy = TrackingProtectionPolicy.strict()) - - /** - * Disables tracking protection for this engine session. - */ - abstract fun disableTrackingProtection() + abstract fun updateTrackingProtection(policy: TrackingProtectionPolicy = TrackingProtectionPolicy.strict()) /** * Enables/disables Desktop Mode with an optional ability to reload the session right after. diff --git a/components/concept/engine/src/test/java/mozilla/components/concept/engine/EngineSessionTest.kt b/components/concept/engine/src/test/java/mozilla/components/concept/engine/EngineSessionTest.kt index 5205c0c2a38..989724922b3 100644 --- a/components/concept/engine/src/test/java/mozilla/components/concept/engine/EngineSessionTest.kt +++ b/components/concept/engine/src/test/java/mozilla/components/concept/engine/EngineSessionTest.kt @@ -698,9 +698,12 @@ class EngineSessionTest { @Test fun `tracking protection policies have correct categories`() { + val recommendedPolicy = TrackingProtectionPolicy.recommended() - assertEquals(TrackingProtectionPolicy.RECOMMENDED, TrackingProtectionPolicy.recommended()) - + assertEquals( + recommendedPolicy.trackingCategories.sumBy { it.id }, + TrackingCategory.RECOMMENDED.id + ) val strictPolicy = TrackingProtectionPolicy.strict() assertEquals( @@ -952,9 +955,7 @@ open class DummyEngineSession : EngineSession() { override fun goToHistoryIndex(index: Int) {} - override fun enableTrackingProtection(policy: TrackingProtectionPolicy) {} - - override fun disableTrackingProtection() {} + override fun updateTrackingProtection(policy: TrackingProtectionPolicy) {} override fun toggleDesktopMode(enable: Boolean, reload: Boolean) {} diff --git a/components/feature/session/src/main/java/mozilla/components/feature/session/SettingsUseCases.kt b/components/feature/session/src/main/java/mozilla/components/feature/session/SettingsUseCases.kt index 6a324e46f5b..31c6a9b0381 100644 --- a/components/feature/session/src/main/java/mozilla/components/feature/session/SettingsUseCases.kt +++ b/components/feature/session/src/main/java/mozilla/components/feature/session/SettingsUseCases.kt @@ -37,7 +37,7 @@ class SettingsUseCases( engine.settings.trackingProtectionPolicy = policy store.state.forEachEngineSession { engineSession -> - engineSession.enableTrackingProtection(policy) + engineSession.updateTrackingProtection(policy) } engine.clearSpeculativeSession() diff --git a/components/feature/session/src/test/java/mozilla/components/feature/session/SettingsUseCasesTest.kt b/components/feature/session/src/test/java/mozilla/components/feature/session/SettingsUseCasesTest.kt index b226430786c..8b42550fe51 100644 --- a/components/feature/session/src/test/java/mozilla/components/feature/session/SettingsUseCasesTest.kt +++ b/components/feature/session/src/test/java/mozilla/components/feature/session/SettingsUseCasesTest.kt @@ -51,8 +51,8 @@ class SettingsUseCasesTest { useCases.updateTrackingProtection(TrackingProtectionPolicy.none()) verify(settings).trackingProtectionPolicy = TrackingProtectionPolicy.none() - verify(engineSessionA).enableTrackingProtection(TrackingProtectionPolicy.none()) - verify(engineSessionB).enableTrackingProtection(TrackingProtectionPolicy.none()) + verify(engineSessionA).updateTrackingProtection(TrackingProtectionPolicy.none()) + verify(engineSessionB).updateTrackingProtection(TrackingProtectionPolicy.none()) verify(engine).clearSpeculativeSession() reset(engine) @@ -60,8 +60,8 @@ class SettingsUseCasesTest { useCases.updateTrackingProtection(TrackingProtectionPolicy.strict()) verify(settings).trackingProtectionPolicy = TrackingProtectionPolicy.strict() - verify(engineSessionA).enableTrackingProtection(TrackingProtectionPolicy.strict()) - verify(engineSessionB).enableTrackingProtection(TrackingProtectionPolicy.strict()) + verify(engineSessionA).updateTrackingProtection(TrackingProtectionPolicy.strict()) + verify(engineSessionB).updateTrackingProtection(TrackingProtectionPolicy.strict()) verify(engine).clearSpeculativeSession() } } diff --git a/docs/changelog.md b/docs/changelog.md index b579f5a7c3e..093a8711a51 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -15,6 +15,9 @@ permalink: /changelog/ * **feature-downloads**: * 🚒 Bug fixed [issue #9757](https://github.com/mozilla-mobile/android-components/issues/9757) - Remove downloads notification when private tabs are closed. +* **concept-engine**,**browser-engine-gecko**, **browser-engine-gecko-beta**, **browser-engine-gecko-nightly**, **browser-engine-system** + * ⚠️ **This is a breaking change**: `EngineSession`.`enableTrackingProtection()` and `EngineSession`.`disableTrackingProtection()` have been removed, please use `EngineSession`.`enableTrackingProtection()` instead , for more details see [issue #9787](https://github.com/mozilla-mobile/android-components/issues/9787). + * **feature-push** * ⚠️ **This is a breaking change**: Removed `databasePath` from `RustPushConnection` constructor and added `context`. The file path is now queries lazily.