From 8fdc655450803421ef55f2f5b25154b585c40bfd Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Wed, 17 Jul 2019 15:45:48 -0400 Subject: [PATCH] Closes #3788: Expose to which category a blocked tracker belongs. --- .../engine/gecko/GeckoEngineSession.kt | 38 +++++++++++++- .../engine/gecko/GeckoEngineSessionTest.kt | 22 +++++++-- .../engine/gecko/GeckoEngineSession.kt | 44 ++++++++++++++++- .../engine/gecko/GeckoEngineSessionTest.kt | 21 +++++--- .../engine/gecko/GeckoEngineSession.kt | 38 +++++++++++++- .../engine/gecko/GeckoEngineSessionTest.kt | 20 ++++++-- .../browser/engine/system/SystemEngineView.kt | 10 +++- .../components/browser/session/Session.kt | 7 +-- .../browser/session/engine/EngineObserver.kt | 5 +- .../SelectionAwareSessionObserverTest.kt | 3 +- .../components/browser/session/SessionTest.kt | 26 +++++----- .../session/engine/EngineObserverTest.kt | 20 +++++--- .../concept/engine/EngineSession.kt | 3 +- .../engine/content/blocking/Tracker.kt | 16 ++++++ .../concept/engine/EngineSessionTest.kt | 49 +++++++++++-------- docs/changelog.md | 5 ++ 16 files changed, 262 insertions(+), 65 deletions(-) create mode 100644 components/concept/engine/src/main/java/mozilla/components/concept/engine/content/blocking/Tracker.kt 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 37eed2195de..30bc977a5eb 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 @@ -17,6 +17,7 @@ import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.EngineSessionState import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.Settings +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.history.HistoryTrackingDelegate import mozilla.components.concept.engine.manifest.WebAppManifestParser import mozilla.components.concept.engine.request.RequestInterceptor @@ -543,10 +544,45 @@ class GeckoEngineSession( private fun createContentBlockingDelegate() = object : ContentBlocking.Delegate { override fun onContentBlocked(session: GeckoSession, event: ContentBlocking.BlockEvent) { - notifyObservers { onTrackerBlocked(event.uri) } + notifyObservers { + onTrackerBlocked(event.toTracker()) + } } } + @Suppress("LongMethod") + private fun ContentBlocking.BlockEvent.toTracker(): Tracker { + val blockedContentCategories = ArrayList() + + if (categories.contains(ContentBlocking.AT_AD)) { + blockedContentCategories.add(Tracker.Category.Ad) + } + + if (categories.contains(ContentBlocking.AT_ANALYTIC)) { + blockedContentCategories.add(Tracker.Category.Analytic) + } + + if (categories.contains(ContentBlocking.AT_SOCIAL)) { + blockedContentCategories.add(Tracker.Category.Social) + } + + if (categories.contains(ContentBlocking.AT_FINGERPRINTING)) { + blockedContentCategories.add(Tracker.Category.Fingerprinting) + } + + if (categories.contains(ContentBlocking.AT_CRYPTOMINING)) { + blockedContentCategories.add(Tracker.Category.Cryptomining) + } + if (categories.contains(ContentBlocking.AT_CONTENT)) { + blockedContentCategories.add(Tracker.Category.Content) + } + return Tracker(uri, blockedContentCategories) + } + + private operator fun Int.contains(mask: Int): Boolean { + return (this and mask) != 0 + } + private fun createPermissionDelegate() = object : GeckoSession.PermissionDelegate { override fun onContentPermissionRequest( session: GeckoSession, 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 1931fe55be5..311cf9b35ab 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 @@ -16,6 +16,7 @@ import mozilla.components.concept.engine.EngineSession.LoadUrlFlags import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.UnsupportedSettingException +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.history.HistoryTrackingDelegate import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.permission.PermissionRequest @@ -784,17 +785,28 @@ class GeckoEngineSessionTest { val engineSession = GeckoEngineSession(mock(), geckoSessionProvider = geckoSessionProvider) - var trackerBlocked = "" + var trackerBlocked: Tracker? = null engineSession.register(object : EngineSession.Observer { - override fun onTrackerBlocked(url: String) { - trackerBlocked = url + override fun onTrackerBlocked(tracker: Tracker) { + trackerBlocked = tracker } }) captureDelegates() - contentBlockingDelegate.value.onContentBlocked(geckoSession, ContentBlocking.BlockEvent("tracker1", 0)) - assertEquals("tracker1", trackerBlocked) + var geckoCatgories = 0 + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_AD) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_ANALYTIC) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_SOCIAL) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_CRYPTOMINING) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_FINGERPRINTING) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_CONTENT) + + contentBlockingDelegate.value.onContentBlocked(geckoSession, + ContentBlocking.BlockEvent("tracker1", geckoCatgories) + ) + assertEquals("tracker1", trackerBlocked!!.url) + assertTrue(trackerBlocked!!.categories.containsAll(Tracker.Category.values().toList())) } @Test 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 37eed2195de..e576e4ea9ee 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 @@ -17,6 +17,7 @@ import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.EngineSessionState import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.Settings +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.history.HistoryTrackingDelegate import mozilla.components.concept.engine.manifest.WebAppManifestParser import mozilla.components.concept.engine.request.RequestInterceptor @@ -30,6 +31,12 @@ import mozilla.components.support.utils.DownloadUtils import org.json.JSONObject import org.mozilla.geckoview.AllowOrDeny import org.mozilla.geckoview.ContentBlocking +import org.mozilla.geckoview.ContentBlocking.AT_AD +import org.mozilla.geckoview.ContentBlocking.AT_ANALYTIC +import org.mozilla.geckoview.ContentBlocking.AT_CONTENT +import org.mozilla.geckoview.ContentBlocking.AT_CRYPTOMINING +import org.mozilla.geckoview.ContentBlocking.AT_FINGERPRINTING +import org.mozilla.geckoview.ContentBlocking.AT_SOCIAL import org.mozilla.geckoview.GeckoResult import org.mozilla.geckoview.GeckoRuntime import org.mozilla.geckoview.GeckoSession @@ -543,10 +550,45 @@ class GeckoEngineSession( private fun createContentBlockingDelegate() = object : ContentBlocking.Delegate { override fun onContentBlocked(session: GeckoSession, event: ContentBlocking.BlockEvent) { - notifyObservers { onTrackerBlocked(event.uri) } + notifyObservers { + onTrackerBlocked(event.toTracker()) + } } } + @Suppress("LongMethod") + private fun ContentBlocking.BlockEvent.toTracker(): Tracker { + val blockedContentCategories = ArrayList() + + if (categories.contains(AT_AD)) { + blockedContentCategories.add(Tracker.Category.Ad) + } + + if (categories.contains(AT_ANALYTIC)) { + blockedContentCategories.add(Tracker.Category.Analytic) + } + + if (categories.contains(AT_SOCIAL)) { + blockedContentCategories.add(Tracker.Category.Social) + } + + if (categories.contains(AT_FINGERPRINTING)) { + blockedContentCategories.add(Tracker.Category.Fingerprinting) + } + + if (categories.contains(AT_CRYPTOMINING)) { + blockedContentCategories.add(Tracker.Category.Cryptomining) + } + if (categories.contains(AT_CONTENT)) { + blockedContentCategories.add(Tracker.Category.Content) + } + return Tracker(uri, blockedContentCategories) + } + + private operator fun Int.contains(mask: Int): Boolean { + return (this and mask) != 0 + } + private fun createPermissionDelegate() = object : GeckoSession.PermissionDelegate { override fun onContentPermissionRequest( session: GeckoSession, 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 1931fe55be5..390e5de5b5e 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 @@ -16,6 +16,7 @@ import mozilla.components.concept.engine.EngineSession.LoadUrlFlags import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.UnsupportedSettingException +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.history.HistoryTrackingDelegate import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.permission.PermissionRequest @@ -784,17 +785,25 @@ class GeckoEngineSessionTest { val engineSession = GeckoEngineSession(mock(), geckoSessionProvider = geckoSessionProvider) - var trackerBlocked = "" + var trackerBlocked: Tracker? = null engineSession.register(object : EngineSession.Observer { - override fun onTrackerBlocked(url: String) { - trackerBlocked = url + override fun onTrackerBlocked(tracker: Tracker) { + trackerBlocked = tracker } }) captureDelegates() - - contentBlockingDelegate.value.onContentBlocked(geckoSession, ContentBlocking.BlockEvent("tracker1", 0)) - assertEquals("tracker1", trackerBlocked) + var geckoCatgories = 0 + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_AD) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_ANALYTIC) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_SOCIAL) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_CRYPTOMINING) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_FINGERPRINTING) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_CONTENT) + + contentBlockingDelegate.value.onContentBlocked(geckoSession, ContentBlocking.BlockEvent("tracker1", geckoCatgories)) + assertEquals("tracker1", trackerBlocked!!.url) + assertTrue(trackerBlocked!!.categories.containsAll(Tracker.Category.values().toList())) } @Test 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 4c0ad83f050..d8dc9e6c5c1 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 @@ -20,6 +20,7 @@ import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.Settings import mozilla.components.concept.engine.history.HistoryTrackingDelegate import mozilla.components.concept.engine.request.RequestInterceptor +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse import mozilla.components.concept.storage.VisitType import mozilla.components.support.ktx.android.util.Base64 @@ -538,10 +539,45 @@ class GeckoEngineSession( private fun createContentBlockingDelegate() = object : ContentBlocking.Delegate { override fun onContentBlocked(session: GeckoSession, event: ContentBlocking.BlockEvent) { - notifyObservers { onTrackerBlocked(event.uri) } + notifyObservers { + onTrackerBlocked(event.toTracker()) + } } } + @Suppress("LongMethod") + private fun ContentBlocking.BlockEvent.toTracker(): Tracker { + val blockedContentCategories = ArrayList() + + if (categories.contains(ContentBlocking.AT_AD)) { + blockedContentCategories.add(Tracker.Category.Ad) + } + + if (categories.contains(ContentBlocking.AT_ANALYTIC)) { + blockedContentCategories.add(Tracker.Category.Analytic) + } + + if (categories.contains(ContentBlocking.AT_SOCIAL)) { + blockedContentCategories.add(Tracker.Category.Social) + } + + if (categories.contains(ContentBlocking.AT_FINGERPRINTING)) { + blockedContentCategories.add(Tracker.Category.Fingerprinting) + } + + if (categories.contains(ContentBlocking.AT_CRYPTOMINING)) { + blockedContentCategories.add(Tracker.Category.Cryptomining) + } + if (categories.contains(ContentBlocking.AT_CONTENT)) { + blockedContentCategories.add(Tracker.Category.Content) + } + return Tracker(uri, blockedContentCategories) + } + + private operator fun Int.contains(mask: Int): Boolean { + return (this and mask) != 0 + } + private fun createPermissionDelegate() = object : GeckoSession.PermissionDelegate { override fun onContentPermissionRequest( session: GeckoSession, 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 db352466b88..20b72034d49 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 @@ -16,6 +16,7 @@ import mozilla.components.concept.engine.EngineSession.LoadUrlFlags import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.UnsupportedSettingException +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.history.HistoryTrackingDelegate import mozilla.components.concept.engine.permission.PermissionRequest import mozilla.components.concept.engine.request.RequestInterceptor @@ -759,17 +760,26 @@ class GeckoEngineSessionTest { val engineSession = GeckoEngineSession(mock(), geckoSessionProvider = geckoSessionProvider) - var trackerBlocked = "" + var trackerBlocked: Tracker? = null engineSession.register(object : EngineSession.Observer { - override fun onTrackerBlocked(url: String) { - trackerBlocked = url + override fun onTrackerBlocked(tracker: Tracker) { + trackerBlocked = tracker } }) captureDelegates() - contentBlockingDelegate.value.onContentBlocked(geckoSession, ContentBlocking.BlockEvent("tracker1", 0)) - assertEquals("tracker1", trackerBlocked) + var geckoCatgories = 0 + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_AD) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_ANALYTIC) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_SOCIAL) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_CRYPTOMINING) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_FINGERPRINTING) + geckoCatgories = geckoCatgories.or(ContentBlocking.AT_CONTENT) + + contentBlockingDelegate.value.onContentBlocked(geckoSession, ContentBlocking.BlockEvent("tracker1", geckoCatgories)) + assertEquals("tracker1", trackerBlocked!!.url) + assertTrue(trackerBlocked!!.categories.containsAll(Tracker.Category.values().toList())) } @Test diff --git a/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt b/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt index 1a01f56cf01..7382de7a85c 100644 --- a/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt +++ b/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt @@ -52,6 +52,7 @@ import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy import mozilla.components.concept.engine.EngineView import mozilla.components.concept.engine.HitResult +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.prompt.PromptRequest import mozilla.components.concept.engine.request.RequestInterceptor.InterceptionResponse import mozilla.components.concept.storage.VisitType @@ -214,7 +215,14 @@ class SystemEngineView @JvmOverloads constructor( if (!request.isForMainFrame && getOrCreateUrlMatcher(resources, it).matches(resourceUri, Uri.parse(session?.currentUrl))) { - session?.internalNotifyObservers { onTrackerBlocked(resourceUri.toString()) } + session?.internalNotifyObservers { + onTrackerBlocked( + Tracker( + resourceUri.toString(), + emptyList() + ) + ) + } return WebResourceResponse(null, null, null) } } diff --git a/components/browser/session/src/main/java/mozilla/components/browser/session/Session.kt b/components/browser/session/src/main/java/mozilla/components/browser/session/Session.kt index 74c8109456f..3d131db8e5f 100644 --- a/components/browser/session/src/main/java/mozilla/components/browser/session/Session.kt +++ b/components/browser/session/src/main/java/mozilla/components/browser/session/Session.kt @@ -21,6 +21,7 @@ import mozilla.components.browser.state.action.ContentAction.UpdateTitleAction import mozilla.components.browser.state.action.ContentAction.UpdateUrlAction import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.HitResult +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.media.Media import mozilla.components.concept.engine.media.RecordingDevice @@ -81,7 +82,7 @@ class Session( fun onWebAppManifestChanged(session: Session, manifest: WebAppManifest?) = Unit fun onDownload(session: Session, download: Download): Boolean = false fun onTrackerBlockingEnabledChanged(session: Session, blockingEnabled: Boolean) = Unit - fun onTrackerBlocked(session: Session, blocked: String, all: List) = Unit + fun onTrackerBlocked(session: Session, tracker: Tracker, all: List) = Unit fun onLongPress(session: Session, hitResult: HitResult): Boolean = false fun onFindResult(session: Session, result: FindResult) = Unit fun onDesktopModeChanged(session: Session, enabled: Boolean) = Unit @@ -300,9 +301,9 @@ class Session( } /** - * List of URIs that have been blocked in this session. + * List of [Tracker]s that have been blocked in this session. */ - var trackersBlocked: List by Delegates.observable(emptyList()) { _, old, new -> + var trackersBlocked: List by Delegates.observable(emptyList()) { _, old, new -> notifyObservers(old, new) { if (new.isNotEmpty()) { onTrackerBlocked(this@Session, new.last(), new) diff --git a/components/browser/session/src/main/java/mozilla/components/browser/session/engine/EngineObserver.kt b/components/browser/session/src/main/java/mozilla/components/browser/session/engine/EngineObserver.kt index 04c3f579a76..af66e0cb024 100644 --- a/components/browser/session/src/main/java/mozilla/components/browser/session/engine/EngineObserver.kt +++ b/components/browser/session/src/main/java/mozilla/components/browser/session/engine/EngineObserver.kt @@ -12,6 +12,7 @@ import mozilla.components.browser.session.engine.request.LoadRequestMetadata import mozilla.components.browser.session.engine.request.LoadRequestOption import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.HitResult +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.media.Media import mozilla.components.concept.engine.media.RecordingDevice @@ -88,8 +89,8 @@ internal class EngineObserver( ?: "", issuer ?: "") } - override fun onTrackerBlocked(url: String) { - session.trackersBlocked += url + override fun onTrackerBlocked(tracker: Tracker) { + session.trackersBlocked += tracker } override fun onTrackerBlockingEnabledChange(enabled: Boolean) { diff --git a/components/browser/session/src/test/java/mozilla/components/browser/session/SelectionAwareSessionObserverTest.kt b/components/browser/session/src/test/java/mozilla/components/browser/session/SelectionAwareSessionObserverTest.kt index 09a6726dfcf..44dbddca3c0 100644 --- a/components/browser/session/src/test/java/mozilla/components/browser/session/SelectionAwareSessionObserverTest.kt +++ b/components/browser/session/src/test/java/mozilla/components/browser/session/SelectionAwareSessionObserverTest.kt @@ -6,6 +6,7 @@ package mozilla.components.browser.session import android.graphics.Bitmap import mozilla.components.concept.engine.HitResult +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.support.test.mock import org.junit.Assert.assertEquals import org.junit.Assert.assertNull @@ -147,7 +148,7 @@ class SelectionAwareSessionObserverTest { observer.onCustomTabConfigChanged(session, null) observer.onDownload(session, Mockito.mock(Download::class.java)) observer.onTrackerBlockingEnabledChanged(session, true) - observer.onTrackerBlocked(session, "", emptyList()) + observer.onTrackerBlocked(session, Tracker(""), emptyList()) observer.onLongPress(session, Mockito.mock(HitResult::class.java)) observer.onFindResult(session, Mockito.mock(Session.FindResult::class.java)) observer.onDesktopModeChanged(session, true) diff --git a/components/browser/session/src/test/java/mozilla/components/browser/session/SessionTest.kt b/components/browser/session/src/test/java/mozilla/components/browser/session/SessionTest.kt index 7bdc5d802be..27653e5baa5 100644 --- a/components/browser/session/src/test/java/mozilla/components/browser/session/SessionTest.kt +++ b/components/browser/session/src/test/java/mozilla/components/browser/session/SessionTest.kt @@ -17,6 +17,7 @@ import mozilla.components.browser.session.tab.CustomTabConfig import mozilla.components.browser.state.action.ContentAction import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.HitResult +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.manifest.Size import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.media.Media @@ -564,23 +565,26 @@ class SessionTest { val session = Session("https://www.mozilla.org") session.register(observer) - session.trackersBlocked += "trackerUrl1" + val tracker1 = Tracker("trackerUrl1") + val tracker2 = Tracker("trackerUrl2") + + session.trackersBlocked += tracker1 verify(observer).onTrackerBlocked( eq(session), - eq("trackerUrl1"), - eq(listOf("trackerUrl1"))) + eq(tracker1), + eq(listOf(tracker1))) - assertEquals(listOf("trackerUrl1"), session.trackersBlocked) + assertEquals(listOf(tracker1), session.trackersBlocked) - session.trackersBlocked += "trackerUrl2" + session.trackersBlocked += tracker2 verify(observer).onTrackerBlocked( eq(session), - eq("trackerUrl2"), - eq(listOf("trackerUrl1", "trackerUrl2"))) + eq(tracker2), + eq(listOf(tracker1, tracker2))) - assertEquals(listOf("trackerUrl1", "trackerUrl2"), session.trackersBlocked) + assertEquals(listOf(tracker1, tracker2), session.trackersBlocked) session.trackersBlocked = emptyList() verifyNoMoreInteractions(observer) @@ -713,7 +717,7 @@ class SessionTest { defaultObserver.onCustomTabConfigChanged(session, null) defaultObserver.onDownload(session, mock(Download::class.java)) defaultObserver.onTrackerBlockingEnabledChanged(session, true) - defaultObserver.onTrackerBlocked(session, "", emptyList()) + defaultObserver.onTrackerBlocked(session, mock(), emptyList()) defaultObserver.onLongPress(session, mock(HitResult::class.java)) defaultObserver.onFindResult(session, mock(Session.FindResult::class.java)) defaultObserver.onDesktopModeChanged(session, true) @@ -892,12 +896,12 @@ class SessionTest { (1..3).map { val def = GlobalScope.async(IO) { session.trackersBlocked = emptyList() - session.trackersBlocked += "test" + session.trackersBlocked += Tracker("test") session.trackersBlocked = emptyList() } val def2 = GlobalScope.async(IO) { session.trackersBlocked = emptyList() - session.trackersBlocked += "test" + session.trackersBlocked += Tracker("test") session.trackersBlocked = emptyList() } def.await() 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 1af6360033d..90d2265d99f 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 @@ -11,6 +11,7 @@ import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.EngineSessionState import mozilla.components.concept.engine.HitResult import mozilla.components.concept.engine.Settings +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.media.Media import mozilla.components.concept.engine.permission.PermissionRequest @@ -158,11 +159,14 @@ class EngineObserverTest { engineSession.disableTrackingProtection() assertFalse(session.trackerBlockingEnabled) - observer.onTrackerBlocked("tracker1") - assertEquals(listOf("tracker1"), session.trackersBlocked) + val tracker1 = Tracker("tracker1", emptyList()) + val tracker2 = Tracker("tracker2", emptyList()) - observer.onTrackerBlocked("tracker2") - assertEquals(listOf("tracker1", "tracker2"), session.trackersBlocked) + observer.onTrackerBlocked(tracker1) + assertEquals(listOf(tracker1), session.trackersBlocked) + + observer.onTrackerBlocked(tracker2) + assertEquals(listOf(tracker1, tracker2), session.trackersBlocked) } @Test @@ -200,9 +204,11 @@ class EngineObserverTest { val session = Session("https://www.mozilla.org") val observer = EngineObserver(session) - observer.onTrackerBlocked("tracker1") - observer.onTrackerBlocked("tracker2") - assertEquals(listOf("tracker1", "tracker2"), session.trackersBlocked) + val tracker1 = Tracker("tracker1") + val tracker2 = Tracker("tracker2") + observer.onTrackerBlocked(tracker1) + observer.onTrackerBlocked(tracker2) + assertEquals(listOf(tracker1, tracker2), session.trackersBlocked) observer.onLoadingStateChange(true) assertEquals(emptyList(), session.trackersBlocked) 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 3bba0cf382c..775f4afc45e 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 @@ -8,6 +8,7 @@ import android.graphics.Bitmap import androidx.annotation.CallSuper 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 import mozilla.components.concept.engine.manifest.WebAppManifest import mozilla.components.concept.engine.media.Media import mozilla.components.concept.engine.media.RecordingDevice @@ -38,7 +39,7 @@ abstract class EngineSession( fun onNavigationStateChange(canGoBack: Boolean? = null, canGoForward: Boolean? = null) = Unit fun onSecurityChange(secure: Boolean, host: String? = null, issuer: String? = null) = Unit fun onTrackerBlockingEnabledChange(enabled: Boolean) = Unit - fun onTrackerBlocked(url: String) = Unit + fun onTrackerBlocked(tracker: Tracker) = Unit fun onLongPress(hitResult: HitResult) = Unit fun onDesktopModeChange(enabled: Boolean) = Unit fun onFind(text: String) = Unit diff --git a/components/concept/engine/src/main/java/mozilla/components/concept/engine/content/blocking/Tracker.kt b/components/concept/engine/src/main/java/mozilla/components/concept/engine/content/blocking/Tracker.kt new file mode 100644 index 00000000000..20811de53f6 --- /dev/null +++ b/components/concept/engine/src/main/java/mozilla/components/concept/engine/content/blocking/Tracker.kt @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.concept.engine.content.blocking + +/** + * Represents a blocked content tracker. + * @property url The URL of the tracker. + * @property categories A list of categories that this [Tracker] belongs. + */ +class Tracker(val url: String, val categories: List = emptyList()) { + enum class Category { + Ad, Analytic, Social, Cryptomining, Fingerprinting, Content + } +} 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 a20faf212db..8dd4922b4e3 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 @@ -7,6 +7,7 @@ package mozilla.components.concept.engine import android.graphics.Bitmap import mozilla.components.concept.engine.EngineSession.LoadUrlFlags import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy +import mozilla.components.concept.engine.content.blocking.Tracker import mozilla.components.concept.engine.media.Media import mozilla.components.concept.engine.permission.PermissionRequest import mozilla.components.concept.engine.window.WindowRequest @@ -38,6 +39,7 @@ class EngineSessionTest { val mediaAdded: Media = mock() val mediaRemoved: Media = mock() + val tracker = Tracker("tracker") session.notifyInternalObservers { onLocationChange("https://www.mozilla.org") } session.notifyInternalObservers { onLocationChange("https://www.firefox.com") } @@ -46,7 +48,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLoadingStateChange(true) } session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } - session.notifyInternalObservers { onTrackerBlocked("tracker") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } session.notifyInternalObservers { onDesktopModeChange(true) } session.notifyInternalObservers { onFind("search") } @@ -70,7 +72,7 @@ class EngineSessionTest { verify(observer).onLoadingStateChange(true) verify(observer).onSecurityChange(true, "mozilla.org", "issuer") verify(observer).onTrackerBlockingEnabledChange(true) - verify(observer).onTrackerBlocked("tracker") + verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) verify(observer).onDesktopModeChange(true) verify(observer).onFind("search") @@ -99,6 +101,8 @@ class EngineSessionTest { val windowRequest = mock(WindowRequest::class.java) val otherWindowRequest = mock(WindowRequest::class.java) val emptyBitmap = spy(Bitmap::class.java) + val tracker = Tracker("tracker") + session.register(observer) session.notifyInternalObservers { onLocationChange("https://www.mozilla.org") } @@ -106,7 +110,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLoadingStateChange(true) } session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } - session.notifyInternalObservers { onTrackerBlocked("tracker") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } session.notifyInternalObservers { onDesktopModeChange(true) } session.notifyInternalObservers { onFind("search") } @@ -129,7 +133,7 @@ class EngineSessionTest { session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(false) } session.notifyInternalObservers { onSecurityChange(false, "", "") } - session.notifyInternalObservers { onTrackerBlocked("tracker2") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(false) } session.notifyInternalObservers { onLongPress(otherHitResult) } session.notifyInternalObservers { onDesktopModeChange(false) } @@ -152,7 +156,7 @@ class EngineSessionTest { verify(observer).onLoadingStateChange(true) verify(observer).onSecurityChange(true, "mozilla.org", "issuer") verify(observer).onTrackerBlockingEnabledChange(true) - verify(observer).onTrackerBlocked("tracker") + verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) verify(observer).onDesktopModeChange(true) verify(observer).onFind("search") @@ -171,7 +175,7 @@ class EngineSessionTest { verify(observer, never()).onLoadingStateChange(false) verify(observer, never()).onSecurityChange(false, "", "") verify(observer, never()).onTrackerBlockingEnabledChange(false) - verify(observer, never()).onTrackerBlocked("tracker2") + verify(observer, never()).onTrackerBlocked(Tracker("Tracker")) verify(observer, never()).onLongPress(otherHitResult) verify(observer, never()).onDesktopModeChange(false) verify(observer, never()).onFind("search2") @@ -201,6 +205,8 @@ class EngineSessionTest { val otherWindowRequest = mock(WindowRequest::class.java) val otherHitResult = HitResult.UNKNOWN("file://foobaz") val emptyBitmap = spy(Bitmap::class.java) + val tracker = Tracker("tracker") + session.register(observer) session.register(otherObserver) @@ -209,7 +215,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLoadingStateChange(true) } session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } - session.notifyInternalObservers { onTrackerBlocked("tracker") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } session.notifyInternalObservers { onDesktopModeChange(true) } session.notifyInternalObservers { onFind("search") } @@ -228,7 +234,7 @@ class EngineSessionTest { session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(false) } session.notifyInternalObservers { onSecurityChange(false, "", "") } - session.notifyInternalObservers { onTrackerBlocked("tracker2") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(false) } session.notifyInternalObservers { onLongPress(otherHitResult) } session.notifyInternalObservers { onDesktopModeChange(false) } @@ -247,7 +253,7 @@ class EngineSessionTest { verify(observer).onLoadingStateChange(true) verify(observer).onSecurityChange(true, "mozilla.org", "issuer") verify(observer).onTrackerBlockingEnabledChange(true) - verify(observer).onTrackerBlocked("tracker") + verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) verify(observer).onDesktopModeChange(true) verify(observer).onFind("search") @@ -264,7 +270,7 @@ class EngineSessionTest { verify(observer, never()).onLoadingStateChange(false) verify(observer, never()).onSecurityChange(false, "", "") verify(observer, never()).onTrackerBlockingEnabledChange(false) - verify(observer, never()).onTrackerBlocked("tracker2") + verify(observer, never()).onTrackerBlocked(Tracker("Tracker")) verify(observer, never()).onLongPress(otherHitResult) verify(observer, never()).onDesktopModeChange(false) verify(observer, never()).onFind("search2") @@ -281,7 +287,7 @@ class EngineSessionTest { verify(otherObserver, never()).onLoadingStateChange(false) verify(otherObserver, never()).onSecurityChange(false, "", "") verify(otherObserver, never()).onTrackerBlockingEnabledChange(false) - verify(otherObserver, never()).onTrackerBlocked("tracker2") + verify(otherObserver, never()).onTrackerBlocked(Tracker("Tracker")) verify(otherObserver, never()).onLongPress(otherHitResult) verify(otherObserver, never()).onDesktopModeChange(false) verify(otherObserver, never()).onFind("search2") @@ -305,6 +311,8 @@ class EngineSessionTest { val windowRequest = mock(WindowRequest::class.java) val otherWindowRequest = mock(WindowRequest::class.java) val emptyBitmap = spy(Bitmap::class.java) + val tracker = Tracker("tracker") + session.register(observer) session.notifyInternalObservers { onLocationChange("https://www.mozilla.org") } @@ -312,7 +320,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLoadingStateChange(true) } session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } - session.notifyInternalObservers { onTrackerBlocked("tracker") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } session.notifyInternalObservers { onDesktopModeChange(true) } session.notifyInternalObservers { onFind("search") } @@ -331,7 +339,7 @@ class EngineSessionTest { session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(false) } session.notifyInternalObservers { onSecurityChange(false, "", "") } - session.notifyInternalObservers { onTrackerBlocked("tracker2") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(false) } session.notifyInternalObservers { onLongPress(otherHitResult) } session.notifyInternalObservers { onDesktopModeChange(false) } @@ -350,7 +358,7 @@ class EngineSessionTest { verify(observer).onLoadingStateChange(true) verify(observer).onSecurityChange(true, "mozilla.org", "issuer") verify(observer).onTrackerBlockingEnabledChange(true) - verify(observer).onTrackerBlocked("tracker") + verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) verify(observer).onDesktopModeChange(true) verify(observer).onFind("search") @@ -367,7 +375,7 @@ class EngineSessionTest { verify(observer, never()).onLoadingStateChange(false) verify(observer, never()).onSecurityChange(false, "", "") verify(observer, never()).onTrackerBlockingEnabledChange(false) - verify(observer, never()).onTrackerBlocked("tracker2") + verify(observer, never()).onTrackerBlocked(Tracker("Tracker")) verify(observer, never()).onLongPress(otherHitResult) verify(observer, never()).onDesktopModeChange(false) verify(observer, never()).onFind("search2") @@ -390,6 +398,7 @@ class EngineSessionTest { val windowRequest = mock(WindowRequest::class.java) val emptyBitmap = spy(Bitmap::class.java) val observer = mock(EngineSession.Observer::class.java) + val tracker = Tracker("tracker") session.register(observer) otherSession.notifyInternalObservers { onLocationChange("https://www.mozilla.org") } @@ -398,7 +407,7 @@ class EngineSessionTest { otherSession.notifyInternalObservers { onLoadingStateChange(true) } otherSession.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } otherSession.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } - otherSession.notifyInternalObservers { onTrackerBlocked("tracker") } + otherSession.notifyInternalObservers { onTrackerBlocked(tracker) } otherSession.notifyInternalObservers { onLongPress(unknownHitResult) } otherSession.notifyInternalObservers { onDesktopModeChange(true) } otherSession.notifyInternalObservers { onFind("search") } @@ -415,7 +424,7 @@ class EngineSessionTest { verify(observer, never()).onLoadingStateChange(true) verify(observer, never()).onSecurityChange(true, "mozilla.org", "issuer") verify(observer, never()).onTrackerBlockingEnabledChange(true) - verify(observer, never()).onTrackerBlocked("tracker") + verify(observer, never()).onTrackerBlocked(tracker) verify(observer, never()).onLongPress(unknownHitResult) verify(observer, never()).onDesktopModeChange(true) verify(observer, never()).onFind("search") @@ -433,7 +442,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLoadingStateChange(true) } session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } - session.notifyInternalObservers { onTrackerBlocked("tracker") } + session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } session.notifyInternalObservers { onDesktopModeChange(false) } session.notifyInternalObservers { onFind("search") } @@ -450,7 +459,7 @@ class EngineSessionTest { verify(observer, times(1)).onLoadingStateChange(true) verify(observer, times(1)).onSecurityChange(true, "mozilla.org", "issuer") verify(observer, times(1)).onTrackerBlockingEnabledChange(true) - verify(observer, times(1)).onTrackerBlocked("tracker") + verify(observer, times(1)).onTrackerBlocked(tracker) verify(observer, times(1)).onLongPress(unknownHitResult) verify(observer, times(1)).onDesktopModeChange(false) verify(observer, times(1)).onFind("search") @@ -613,7 +622,7 @@ class EngineSessionTest { defaultObserver.onExternalResource("", "") defaultObserver.onDesktopModeChange(true) defaultObserver.onSecurityChange(true) - defaultObserver.onTrackerBlocked("") + defaultObserver.onTrackerBlocked(mock()) defaultObserver.onTrackerBlockingEnabledChange(true) defaultObserver.onFindResult(0, 0, false) defaultObserver.onFind("text") diff --git a/docs/changelog.md b/docs/changelog.md index 345d1a83e6b..9880ee2e73c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -11,6 +11,11 @@ permalink: /changelog/ * [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt) * [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt) +* **concept-engine** and **browser-session** + * ⚠️ **This is a breaking change**: Function signature changed `Session.Observer.onTrackerBlocked(session: Session, blocked: String, all: List) = Unit` from to `Session.Observer.onTrackerBlocked(session: Session, tracker: Tracker, all: List) = Unit` + * ⚠️ **This is a breaking change**: Function signature changed `EngineSession.Observer.onTrackerBlocked(url: String) = Unit` from to `EngineSession.Observer.onTrackerBlocked(tracker: Tracker) = Unit` + * Added: To provide more details about a blocked content, we introduced a new class called `Tracker` this contains information like the `url` and `categories` of the `Tracker`. Among the categories we have `Ad`, `Analytic`, `Social`,`Cryptomining`, `Fingerprinting` and `Content`. + * **All components** * Increased `compileSdkVersion` to 29 (Android Q)