Files
cromite/build/patches/eyeo-133.0.6943.49-android_api.patch

2229 lines
88 KiB
Diff

From: chromium-sdk <project_26591639_bot@noreply.gitlab.com>
Date: Fri, 14 Feb 2025 08:26:39 +0100
Subject: eyeo Browser Ad filtering Solution: Android API Module
Based on Chromium 133.0.6943.49
Pre-requisites: eyeo Browser Ad filtering Solution: Base Module
---
chrome/android/BUILD.gn | 12 +
chrome/android/chrome_java_sources.gni | 4 +
.../browser/adblock/TabIdTranslator.java | 36 ++
chrome/browser/BUILD.gn | 4 +
.../android/adblock/tab_id_translator_jni.cc | 43 ++
components/adblock/android/BUILD.gn | 107 +++++
.../adblock/android/adblock_controller_jni.cc | 133 ++++++
.../filtering_configuration_android.cc | 246 ++++++++++
.../android/filtering_configuration_android.h | 94 ++++
.../components/adblock/AdblockController.java | 283 ++++++++++++
.../components/adblock/AdblockSwitches.java | 22 +
.../components/adblock/ContentType.java | 61 +++
.../adblock/FilteringConfiguration.java | 424 ++++++++++++++++++
.../ResourceClassificationNotifier.java | 233 ++++++++++
.../adblock/ResourceFilteringCounters.java | 111 +++++
...esource_classification_notifier_android.cc | 166 +++++++
...resource_classification_notifier_android.h | 72 +++
17 files changed, 2051 insertions(+)
create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/adblock/TabIdTranslator.java
create mode 100644 chrome/browser/android/adblock/tab_id_translator_jni.cc
create mode 100644 components/adblock/android/BUILD.gn
create mode 100644 components/adblock/android/adblock_controller_jni.cc
create mode 100644 components/adblock/android/filtering_configuration_android.cc
create mode 100644 components/adblock/android/filtering_configuration_android.h
create mode 100644 components/adblock/android/java/src/org/chromium/components/adblock/AdblockController.java
create mode 100644 components/adblock/android/java/src/org/chromium/components/adblock/AdblockSwitches.java
create mode 100644 components/adblock/android/java/src/org/chromium/components/adblock/ContentType.java
create mode 100644 components/adblock/android/java/src/org/chromium/components/adblock/FilteringConfiguration.java
create mode 100644 components/adblock/android/java/src/org/chromium/components/adblock/ResourceClassificationNotifier.java
create mode 100644 components/adblock/android/java/src/org/chromium/components/adblock/ResourceFilteringCounters.java
create mode 100644 components/adblock/android/resource_classification_notifier_android.cc
create mode 100644 components/adblock/android/resource_classification_notifier_android.h
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1,6 +1,9 @@
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
import("//build/config/android/config.gni")
import("//build/config/cronet/config.gni")
@@ -574,6 +577,7 @@ if (_is_default_toolchain) {
"//chrome/browser/xsurface:java",
"//chrome/browser/xsurface_provider:dependency_provider_impl_java",
"//chrome/browser/xsurface_provider:java",
+ "//components/adblock/android:adblock_controller_java",
"//components/android_autofill/browser:java",
"//components/autofill/android:autofill_features_java",
"//components/autofill/android:autofill_java",
@@ -1529,6 +1533,7 @@ if (_is_default_toolchain) {
"//chrome/test/data/translate/",
"//chrome/test/data/webauthn/",
"//chrome/test/media_router/resources/",
+ "//components/test/data/adblock/",
"//components/test/data/autofill/",
"//components/test/data/payments/",
"//content/test/data/browsing_data/",
@@ -3153,6 +3158,12 @@ if (_is_default_toolchain) {
sources += [ "java/src/org/chromium/chrome/browser/media/MediaCapturePickerManagerBridge.java" ]
}
+ ### Android API module start
+ sources +=
+ [ "java/src/org/chromium/chrome/browser/adblock/TabIdTranslator.java" ]
+
+ ### Android API module end
+
# Used for testing only, should not be shipped to end users.
if (enable_offline_pages_harness) {
sources += [ "java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java" ]
@@ -3244,6 +3255,7 @@ if (_is_default_toolchain) {
"//chrome/browser/ui/plus_addresses/android:jni_headers",
"//chrome/browser/util:jni_headers",
"//chrome/browser/webauthn/android:jni_headers",
+ "//components/adblock/android:jni_headers",
"//components/browser_ui/device_lock/android:device_lock_bridge_jni_headers",
"//components/content_relationship_verification/android:jni_headers",
"//components/image_fetcher:jni_headers",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1,6 +1,9 @@
# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
import("//content/public/common/features.gni")
@@ -66,6 +69,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/accessibility/settings/ChromeAccessibilitySettingsDelegate.java",
"java/src/org/chromium/chrome/browser/actor/ActorForegroundServiceControllerImpl.java",
"java/src/org/chromium/chrome/browser/actor/ActorForegroundServiceImpl.java",
+ "java/src/org/chromium/chrome/browser/adblock/TabIdTranslator.java",
"java/src/org/chromium/chrome/browser/ai/AiAssistantService.java",
"java/src/org/chromium/chrome/browser/ai/PageSummaryButtonController.java",
"java/src/org/chromium/chrome/browser/ai/SystemAiProvider.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/adblock/TabIdTranslator.java b/chrome/android/java/src/org/chromium/chrome/browser/adblock/TabIdTranslator.java
new file mode 100644
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/adblock/TabIdTranslator.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package chromium.chrome.browser.adblock;
+
+import org.jni_zero.NativeMethods;
+
+import org.chromium.content_public.browser.GlobalRenderFrameHostId;
+
+/**
+ * @brief Helper class to translate AdblockCounters.ResourceInfo.mMainFrameId to TabId.
+ */
+public final class TabIdTranslator {
+ public static int fromRenderFrameHostId(GlobalRenderFrameHostId id) {
+ return TabIdTranslatorJni.get().fromRenderFrameHostId(id.childId(), id.frameRoutingId());
+ }
+
+ @NativeMethods
+ public interface Natives {
+ int fromRenderFrameHostId(int renderProcessId, int renderFrameId);
+ }
+}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3041,6 +3041,10 @@ static_library("browser") {
]
deps += [ "//chrome/browser/password_entry_edit/android" ]
+ ### Android API module start
+ sources += [ "android/adblock/tab_id_translator_jni.cc" ]
+ ### Android API module end
+
deps += [
":delta_file_proto",
":language_data_proto",
diff --git a/chrome/browser/android/adblock/tab_id_translator_jni.cc b/chrome/browser/android/adblock/tab_id_translator_jni.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/android/adblock/tab_id_translator_jni.cc
@@ -0,0 +1,43 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/android/chrome_jni_headers/TabIdTranslator_jni.h"
+#include "chrome/browser/android/tab_android.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+constexpr int kNoTabId = -1;
+}
+
+static jint JNI_TabIdTranslator_FromRenderFrameHostId(JNIEnv* env,
+ jint render_process_id,
+ jint render_frame_id) {
+ auto* web_contents = content::WebContents::FromRenderFrameHost(
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id));
+ if (!web_contents) {
+ return kNoTabId;
+ }
+
+ auto* tab = TabAndroid::FromWebContents(web_contents);
+ if (!tab) {
+ return kNoTabId;
+ }
+
+ return tab->GetAndroidId();
+}
+
+DEFINE_JNI(TabIdTranslator)
diff --git a/components/adblock/android/BUILD.gn b/components/adblock/android/BUILD.gn
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/BUILD.gn
@@ -0,0 +1,107 @@
+# This file is part of eyeo Chromium SDK,
+# Copyright (C) 2006-present eyeo GmbH
+# eyeo Chromium SDK is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3 as
+# published by the Free Software Foundation.
+# eyeo Chromium SDK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+
+import("//build/config/android/rules.gni")
+import("//build/config/locales.gni")
+import("//third_party/jni_zero/jni_zero.gni")
+import("//tools/grit/grit_rule.gni")
+
+source_set("java_bindings") {
+ sources = [
+ "adblock_controller_jni.cc",
+ "filtering_configuration_android.cc",
+ "filtering_configuration_android.h",
+ "resource_classification_notifier_android.cc",
+ "resource_classification_notifier_android.h",
+ ]
+ deps = [
+ ":jni_headers",
+ "//base",
+ "//components/keyed_service/content:content",
+ "//components/user_prefs:user_prefs",
+ ]
+
+ public_deps = [
+ "//components/adblock/content:browser",
+ "//components/adblock/core/configuration",
+ "//components/adblock/core/subscription",
+ "//components/prefs",
+ ]
+}
+
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/adblock/AdblockController.java",
+ "java/src/org/chromium/components/adblock/FilteringConfiguration.java",
+ "java/src/org/chromium/components/adblock/ResourceClassificationNotifier.java",
+ ]
+}
+
+android_library("adblock_controller_java") {
+ sources = [
+ "java/src/org/chromium/components/adblock/AdblockController.java",
+ "java/src/org/chromium/components/adblock/AdblockSwitches.java",
+ "java/src/org/chromium/components/adblock/ContentType.java",
+ "java/src/org/chromium/components/adblock/FilteringConfiguration.java",
+ "java/src/org/chromium/components/adblock/ResourceClassificationNotifier.java",
+ "java/src/org/chromium/components/adblock/ResourceFilteringCounters.java",
+ ]
+
+ srcjar_deps = [ ":jni_headers" ]
+ deps = [
+ "//base:base_java",
+ "//content/public/android:content_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/jni_zero:jni_zero_java",
+ ]
+
+ resources_package = "org.chromium.components.adblock.controller"
+}
+
+android_library("adblock_java_tests_base") {
+ testonly = true
+ sources = [
+ "javatests/src/org/chromium/components/adblock/AdblockControllerTestBase.java",
+ "javatests/src/org/chromium/components/adblock/DefaultSettingsTestBase.java",
+ "javatests/src/org/chromium/components/adblock/FilteringConfigurationTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesCircumventionTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesCspTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesElemhideEmuInvTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesElemhideEmuTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesElemhideTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesExceptionTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesFilterTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesHeaderFilterTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesHelperBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesInlineCssTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesRemoveTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesRewriteTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesServiceWorkersTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesSiteKeyTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesSnippetsTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesWebsocketTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestPagesWildcardDomainTestBase.java",
+ "javatests/src/org/chromium/components/adblock/TestResourceFilteringObserver.java",
+ "javatests/src/org/chromium/components/adblock/TestVerificationUtils.java",
+ ]
+ deps = [
+ ":adblock_controller_java",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//content/public/android:content_full_java",
+ "//content/public/test/android:content_java_test_support",
+ "//net/android:net_java_test_support",
+ "//third_party/androidx:androidx_test_monitor_java",
+ "//third_party/androidx:androidx_test_runner_java",
+ "//third_party/junit:junit",
+ ]
+}
diff --git a/components/adblock/android/adblock_controller_jni.cc b/components/adblock/android/adblock_controller_jni.cc
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/adblock_controller_jni.cc
@@ -0,0 +1,133 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/jni_weak_ref.h"
+#include "base/logging.h"
+#include "components/adblock/android/jni_headers/AdblockController_jni.h"
+#include "components/adblock/content/browser/factories/subscription_service_factory.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_config.h"
+#include "content/public/browser/android/browser_context_handle.h"
+#include "content/public/browser/browser_thread.h"
+
+using base::android::CheckException;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::GetClass;
+using base::android::JavaParamRef;
+using base::android::MethodID;
+using base::android::ScopedJavaLocalRef;
+using base::android::ToJavaArrayOfObjects;
+using base::android::ToJavaArrayOfStrings;
+
+namespace {
+
+ScopedJavaLocalRef<jobject> ToJava(JNIEnv* env,
+ ScopedJavaLocalRef<jclass>& url_class,
+ jmethodID& url_constructor,
+ const std::string& url,
+ const std::string& title,
+ const std::string& version,
+ const std::vector<std::string>& languages,
+ const bool autoinstalled) {
+ ScopedJavaLocalRef<jobject> url_param =
+ ScopedJavaLocalRef<jobject>::Adopt(
+ env, env->NewObject(url_class.obj(), url_constructor,
+ ConvertUTF8ToJavaString(env, url).obj()));
+ CheckException(env);
+ return Java_Subscription_Constructor(env, url_param,
+ ConvertUTF8ToJavaString(env, title),
+ ConvertUTF8ToJavaString(env, version),
+ ToJavaArrayOfStrings(env, languages),
+ autoinstalled ? JNI_TRUE : JNI_FALSE);
+}
+
+std::vector<ScopedJavaLocalRef<jobject>> CSubscriptionsToJObjects(
+ JNIEnv* env,
+ const std::vector<scoped_refptr<adblock::Subscription>>& subscriptions) {
+ ScopedJavaLocalRef<jclass> url_class = GetClass(env, "java/net/URL");
+ jmethodID url_constructor = MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, url_class.obj(), "<init>", "(Ljava/lang/String;)V");
+ std::vector<ScopedJavaLocalRef<jobject>> jobjects;
+ jobjects.reserve(subscriptions.size());
+ for (auto& sub : subscriptions) {
+ jobjects.push_back(ToJava(
+ env, url_class, url_constructor, sub->GetSourceUrl().spec(),
+ sub->GetTitle(), sub->GetCurrentVersion(), std::vector<std::string>{},
+ sub->GetInstallationState() ==
+ adblock::InstalledSubscription::InstallationState::AutoInstalled));
+ }
+ return jobjects;
+}
+
+std::vector<ScopedJavaLocalRef<jobject>> CSubscriptionsToJObjects(
+ JNIEnv* env,
+ std::vector<adblock::KnownSubscriptionInfo>& subscriptions) {
+ ScopedJavaLocalRef<jclass> url_class = GetClass(env, "java/net/URL");
+ jmethodID url_constructor = MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, url_class.obj(), "<init>", "(Ljava/lang/String;)V");
+ std::vector<ScopedJavaLocalRef<jobject>> jobjects;
+ jobjects.reserve(subscriptions.size());
+ for (auto& sub : subscriptions) {
+ if (sub.ui_visibility == adblock::SubscriptionUiVisibility::Visible) {
+ // The checks here are when one makes f.e. adblock:custom visible
+ DCHECK(sub.url.is_valid());
+ if (sub.url.is_valid()) {
+ jobjects.push_back(ToJava(env, url_class, url_constructor,
+ sub.url.spec(), sub.title, "", sub.languages,
+ false));
+ }
+ }
+ }
+ return jobjects;
+}
+
+} // namespace
+
+static base::android::ScopedJavaLocalRef<jobjectArray>
+JNI_AdblockController_GetInstalledSubscriptions(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jbrowser_context_handle) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ auto* subscription_service =
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle));
+ if (!subscription_service) {
+ return ToJavaArrayOfObjects(env,
+ std::vector<ScopedJavaLocalRef<jobject>>{});
+ }
+
+ return ToJavaArrayOfObjects(
+ env, CSubscriptionsToJObjects(
+ env, subscription_service->GetCurrentSubscriptions(
+ subscription_service->GetFilteringConfiguration(
+ adblock::kAdblockFilteringConfigurationName))));
+}
+
+static base::android::ScopedJavaLocalRef<jobjectArray>
+JNI_AdblockController_GetRecommendedSubscriptions(JNIEnv* env) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ auto list = adblock::config::GetKnownSubscriptions();
+ return ToJavaArrayOfObjects(env, CSubscriptionsToJObjects(env, list));
+}
diff --git a/components/adblock/android/filtering_configuration_android.cc b/components/adblock/android/filtering_configuration_android.cc
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/filtering_configuration_android.cc
@@ -0,0 +1,246 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "components/adblock/android/filtering_configuration_android.h"
+
+#include <iterator>
+#include <memory>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "components/adblock/android/jni_headers/FilteringConfiguration_jni.h"
+#include "components/adblock/content/browser/factories/subscription_service_factory.h"
+#include "components/adblock/core/configuration/filtering_configuration.h"
+#include "components/adblock/core/configuration/persistent_filtering_configuration.h"
+#include "components/adblock/core/subscription/subscription_config.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/android/browser_context_handle.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
+using base::android::ToJavaArrayOfStrings;
+
+using namespace adblock;
+
+FilteringConfigurationAndroid::FilteringConfigurationAndroid(
+ JNIEnv* env,
+ const JavaRef<jobject>& jcontroller,
+ const std::string& configuration_name,
+ SubscriptionService* subscription_service,
+ PrefService* pref_service)
+ : subscription_service_(subscription_service),
+ pref_service_(pref_service),
+ java_weak_controller_(env, jcontroller) {
+ subscription_service_->AddObserver(this);
+ auto* existing_configuration =
+ subscription_service_->GetFilteringConfiguration(configuration_name);
+ if (existing_configuration) {
+ filtering_configuration_ptr = existing_configuration;
+ } else {
+ auto new_filtering_configuration =
+ std::make_unique<PersistentFilteringConfiguration>(pref_service_,
+ configuration_name);
+ filtering_configuration_ptr = new_filtering_configuration.get();
+ subscription_service_->InstallFilteringConfiguration(
+ std::move(new_filtering_configuration));
+ }
+ filtering_configuration_ptr->AddObserver(this);
+}
+
+FilteringConfigurationAndroid::~FilteringConfigurationAndroid() {
+ filtering_configuration_ptr->RemoveObserver(this);
+ subscription_service_->UninstallFilteringConfiguration(
+ filtering_configuration_ptr->GetName());
+ subscription_service_->RemoveObserver(this);
+}
+
+void FilteringConfigurationAndroid::Destroy(JNIEnv*) {
+ delete this;
+}
+
+void FilteringConfigurationAndroid::OnEnabledStateChanged(
+ FilteringConfiguration* config) {
+ Notify(config, Java_FilteringConfiguration_enabledStateChanged);
+}
+
+void FilteringConfigurationAndroid::OnFilterListsChanged(
+ FilteringConfiguration* config) {
+ Notify(config, Java_FilteringConfiguration_filterListsChanged);
+}
+
+void FilteringConfigurationAndroid::OnAllowedDomainsChanged(
+ FilteringConfiguration* config) {
+ Notify(config, Java_FilteringConfiguration_allowedDomainsChanged);
+}
+
+void FilteringConfigurationAndroid::OnCustomFiltersChanged(
+ FilteringConfiguration* config) {
+ Notify(config, Java_FilteringConfiguration_customFiltersChanged);
+}
+
+void FilteringConfigurationAndroid::Notify(
+ FilteringConfiguration* config,
+ FilteringConfigurationAndroid::JavaEventListener event_listener_function) {
+ JNIEnv* env = AttachCurrentThread();
+ auto java_controller = java_weak_controller_.get(env);
+ if (!java_controller.is_null()) {
+ event_listener_function(env, java_controller);
+ }
+}
+
+void FilteringConfigurationAndroid::OnSubscriptionInstalled(const GURL& url) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
+ auto java_controller = java_weak_controller_.get(env);
+ if (!java_controller.is_null()) {
+ Java_FilteringConfiguration_onSubscriptionUpdated(env, java_controller,
+ j_url);
+ }
+}
+
+jboolean FilteringConfigurationAndroid::IsEnabled(JNIEnv* env) const {
+ return filtering_configuration_ptr->IsEnabled() ? JNI_TRUE : JNI_FALSE;
+}
+
+void FilteringConfigurationAndroid::SetEnabled(JNIEnv* env,
+ jboolean j_enabled) {
+ filtering_configuration_ptr->SetEnabled(j_enabled == JNI_TRUE);
+}
+
+void FilteringConfigurationAndroid::AddAllowedDomain(
+ JNIEnv* env,
+ const JavaRef<jstring>& allowed_domain) {
+ filtering_configuration_ptr->AddAllowedDomain(
+ ConvertJavaStringToUTF8(allowed_domain));
+}
+
+void FilteringConfigurationAndroid::RemoveAllowedDomain(
+ JNIEnv* env,
+ const JavaRef<jstring>& allowed_domain) {
+ filtering_configuration_ptr->RemoveAllowedDomain(
+ ConvertJavaStringToUTF8(allowed_domain));
+}
+
+ScopedJavaLocalRef<jobjectArray>
+FilteringConfigurationAndroid::GetAllowedDomains(JNIEnv* env) const {
+ return ToJavaArrayOfStrings(env,
+ filtering_configuration_ptr->GetAllowedDomains());
+}
+
+void FilteringConfigurationAndroid::AddCustomFilter(
+ JNIEnv* env,
+ const JavaRef<jstring>& custom_filter) {
+ filtering_configuration_ptr->AddCustomFilter(
+ ConvertJavaStringToUTF8(custom_filter));
+}
+
+void FilteringConfigurationAndroid::RemoveCustomFilter(
+ JNIEnv* env,
+ const JavaRef<jstring>& custom_filter) {
+ filtering_configuration_ptr->RemoveCustomFilter(
+ ConvertJavaStringToUTF8(custom_filter));
+}
+
+ScopedJavaLocalRef<jobjectArray>
+FilteringConfigurationAndroid::GetCustomFilters(JNIEnv* env) const {
+ return ToJavaArrayOfStrings(env,
+ filtering_configuration_ptr->GetCustomFilters());
+}
+
+void FilteringConfigurationAndroid::AddFilterList(
+ JNIEnv* env,
+ const JavaRef<jstring>& url) {
+ filtering_configuration_ptr->AddFilterList(
+ GURL{ConvertJavaStringToUTF8(url)});
+}
+
+void FilteringConfigurationAndroid::RemoveFilterList(
+ JNIEnv* env,
+ const JavaRef<jstring>& url) {
+ filtering_configuration_ptr->RemoveFilterList(
+ GURL{ConvertJavaStringToUTF8(url)});
+}
+
+ScopedJavaLocalRef<jobjectArray> FilteringConfigurationAndroid::GetFilterLists(
+ JNIEnv* env) const {
+ // For simplicity, convert GURL to std::string, pass to Java, and convert
+ // from String to URL. Strings are easier to pass through JNI.
+ std::vector<std::string> urls;
+ std::ranges::transform(filtering_configuration_ptr->GetFilterLists(),
+ std::back_inserter(urls), &GURL::spec);
+ return ToJavaArrayOfStrings(env, urls);
+}
+
+static ScopedJavaLocalRef<jstring>
+JNI_FilteringConfiguration_GetAcceptableAdsUrl(JNIEnv* env) {
+ return ConvertUTF8ToJavaString(env, adblock::AcceptableAdsUrl().spec());
+}
+
+static jlong JNI_FilteringConfiguration_Create(
+ JNIEnv* env,
+ const JavaRef<jobject>& jcontroller,
+ const JavaRef<jstring>& jstring,
+ const JavaRef<jobject>& jbrowser_context_handle) {
+ DCHECK(!jcontroller.is_null());
+ DCHECK(!jbrowser_context_handle.is_null());
+ auto* context =
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle);
+ return reinterpret_cast<jlong>(new FilteringConfigurationAndroid(
+ env, std::move(jcontroller), ConvertJavaStringToUTF8(jstring),
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(context),
+ user_prefs::UserPrefs::Get(context)));
+}
+
+static ScopedJavaLocalRef<jobjectArray>
+JNI_FilteringConfiguration_GetConfigurations(
+ JNIEnv* env,
+ const JavaRef<jobject>& jbrowser_context_handle) {
+ std::vector<std::string> configurations;
+ std::ranges::transform(
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle))
+ ->GetInstalledFilteringConfigurations(),
+ std::back_inserter(configurations),
+ [](adblock::FilteringConfiguration* fc) { return fc->GetName(); });
+ return ToJavaArrayOfStrings(env, configurations);
+}
+
+static jboolean JNI_FilteringConfiguration_IsAutoInstallEnabled(
+ JNIEnv* env,
+ const JavaRef<jobject>& jbrowser_context_handle) {
+ return adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle))
+ ->IsAutoInstallEnabled()
+ ? JNI_TRUE
+ : JNI_FALSE;
+}
+
+static void JNI_FilteringConfiguration_SetAutoInstallEnabled(
+ JNIEnv* env,
+ jboolean j_enabled,
+ const JavaRef<jobject>& jbrowser_context_handle) {
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle))
+ ->SetAutoInstallEnabled(j_enabled == JNI_TRUE);
+}
+
+DEFINE_JNI(FilteringConfiguration)
diff --git a/components/adblock/android/filtering_configuration_android.h b/components/adblock/android/filtering_configuration_android.h
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/filtering_configuration_android.h
@@ -0,0 +1,94 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMPONENTS_ADBLOCK_ANDROID_FILTERING_CONFIGURATION_ANDROID_H_
+#define COMPONENTS_ADBLOCK_ANDROID_FILTERING_CONFIGURATION_ANDROID_H_
+
+#include <map>
+#include <utility>
+#include <vector>
+#include "base/android/jni_weak_ref.h"
+#include "base/memory/raw_ptr.h"
+#include "base/sequence_checker.h"
+#include "components/adblock/core/configuration/filtering_configuration.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_service.h"
+
+class FilteringConfigurationAndroid
+ : public adblock::FilteringConfiguration::Observer,
+ public adblock::SubscriptionService::SubscriptionObserver {
+ public:
+ explicit FilteringConfigurationAndroid(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jcontroller,
+ const std::string& configuration_name,
+ adblock::SubscriptionService* subscription_service,
+ PrefService* pref_service);
+ ~FilteringConfigurationAndroid() override;
+ // Called by Java to destroy this instance.
+ void Destroy(JNIEnv*);
+ void SetEnabled(JNIEnv* env, jboolean j_enabled);
+ jboolean IsEnabled(JNIEnv* env) const;
+ void AddFilterList(JNIEnv* env,
+ const base::android::JavaRef<jstring>& url);
+ void RemoveFilterList(JNIEnv* env,
+ const base::android::JavaRef<jstring>& url);
+ base::android::ScopedJavaLocalRef<jobjectArray> GetFilterLists(
+ JNIEnv* env) const;
+ void AddAllowedDomain(JNIEnv* env,
+ const base::android::JavaRef<jstring>& domain);
+ void RemoveAllowedDomain(JNIEnv* env,
+ const base::android::JavaRef<jstring>& domain);
+ base::android::ScopedJavaLocalRef<jobjectArray> GetAllowedDomains(
+ JNIEnv* env) const;
+ void AddCustomFilter(JNIEnv* env,
+ const base::android::JavaRef<jstring>& filter);
+ void RemoveCustomFilter(JNIEnv* env,
+ const base::android::JavaRef<jstring>& filter);
+ base::android::ScopedJavaLocalRef<jobjectArray> GetCustomFilters(
+ JNIEnv* env) const;
+
+ // FilteringConfiguration::Observer:
+ void OnEnabledStateChanged(adblock::FilteringConfiguration* config) override;
+ void OnFilterListsChanged(adblock::FilteringConfiguration* config) override;
+ void OnAllowedDomainsChanged(
+ adblock::FilteringConfiguration* config) override;
+ void OnCustomFiltersChanged(adblock::FilteringConfiguration* config) override;
+
+ // SubcriptionService::Observer:
+ void OnSubscriptionInstalled(const GURL& subscription_url) override;
+
+ private:
+ using JavaEventListener = void(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
+ void Notify(adblock::FilteringConfiguration* config,
+ JavaEventListener event_listener_function);
+ SEQUENCE_CHECKER(sequence_checker_);
+ raw_ptr<adblock::SubscriptionService> subscription_service_;
+ raw_ptr<PrefService> pref_service_;
+ raw_ptr<adblock::FilteringConfiguration> filtering_configuration_ptr;
+
+ // Direct reference to FilteringConfiguration java class. Kept for as
+ // long as this instance of FilteringConfigurationAndroid lives:
+ // until corresponding Profile gets destroyed. Destruction of Profile triggers
+ // destruction of both C++ FilteringConfigurationAndroid and Java
+ // FilteringConfiguration objects.
+ const JavaObjectWeakGlobalRef java_weak_controller_;
+};
+
+#endif // COMPONENTS_ADBLOCK_ANDROID_FILTERING_CONFIGURATION_ANDROID_H_
diff --git a/components/adblock/android/java/src/org/chromium/components/adblock/AdblockController.java b/components/adblock/android/java/src/org/chromium/components/adblock/AdblockController.java
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/java/src/org/chromium/components/adblock/AdblockController.java
@@ -0,0 +1,283 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.components.adblock;
+
+import androidx.annotation.UiThread;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.NativeMethods;
+
+import org.chromium.base.ResettersForTesting;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.content_public.browser.BrowserContextHandle;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * DEPRECATED, please use {@link FilteringConfiguration} instead.
+ *
+ * @brief Main access point for java UI code to control ad filtering. It calls its native counter
+ * part also AdblockController. It lives in UI thread on the browser process.
+ */
+@Deprecated
+public class AdblockController {
+ private static final String TAG = AdblockController.class.getSimpleName();
+ private FilteringConfiguration mFilteringConfiguration;
+ private BrowserContextHandle mBrowserContextHandle;
+
+ private URL mAcceptableAds;
+
+ private static AdblockController sInstance;
+
+ private AdblockController(BrowserContextHandle contextHandle) {
+ mBrowserContextHandle = contextHandle;
+ mFilteringConfiguration =
+ FilteringConfiguration.createConfiguration("adblock", mBrowserContextHandle);
+ try {
+ mAcceptableAds =
+ new URL("https://easylist-downloads.adblockplus.org/exceptionrules.txt");
+ } catch (java.net.MalformedURLException e) {
+ mAcceptableAds = null;
+ }
+ }
+
+ /**
+ * @return The singleton object.
+ */
+ public static AdblockController getInstance(BrowserContextHandle contextHandle) {
+ // Make sure native libraries are ready to avoid org.chromium.base.JniException
+ LibraryLoader.getInstance().ensureInitialized();
+ ThreadUtils.assertOnUiThread();
+ if (sInstance == null) {
+ sInstance = new AdblockController(contextHandle);
+ }
+ return sInstance;
+ }
+
+ public static void setInstanceForTesting(final AdblockController adblockController) {
+ var oldValue = sInstance;
+ sInstance = adblockController;
+ ResettersForTesting.register(() -> sInstance = oldValue);
+ }
+
+ public static class Subscription {
+ private URL mUrl;
+ private String mTitle;
+ private String mVersion = "";
+ private String[] mLanguages = {};
+ private boolean mAutoInstalled;
+
+ public Subscription(final URL url, final String title, final String version) {
+ this.mUrl = url;
+ this.mTitle = title;
+ this.mVersion = version;
+ }
+
+ @CalledByNative("Subscription")
+ public Subscription(
+ final URL url,
+ final String title,
+ final String version,
+ final String[] languages,
+ boolean autoinstalled) {
+ this.mUrl = url;
+ this.mTitle = title;
+ this.mVersion = version;
+ this.mLanguages = languages;
+ this.mAutoInstalled = autoinstalled;
+ }
+
+ public String title() {
+ return mTitle;
+ }
+
+ public URL url() {
+ return mUrl;
+ }
+
+ public String version() {
+ return mVersion;
+ }
+
+ public String[] languages() {
+ return mLanguages;
+ }
+
+ public boolean autoinstalled() {
+ return mAutoInstalled;
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ if (object == null) return false;
+ if (getClass() != object.getClass()) return false;
+
+ Subscription other = (Subscription) object;
+ return url().equals(other.url());
+ }
+ }
+
+ @UiThread
+ public void setAcceptableAdsEnabled(boolean enabled) {
+ if (enabled) mFilteringConfiguration.addFilterList(mAcceptableAds);
+ else mFilteringConfiguration.removeFilterList(mAcceptableAds);
+ }
+
+ @UiThread
+ public boolean isAcceptableAdsEnabled() {
+ return mFilteringConfiguration.getFilterLists().contains(mAcceptableAds);
+ }
+
+ @UiThread
+ public List<Subscription> getRecommendedSubscriptions() {
+ return (List<Subscription>)
+ (List<?>) Arrays.asList(AdblockControllerJni.get().getRecommendedSubscriptions());
+ }
+
+ @UiThread
+ public void setAutoInstallEnabled(boolean enable) {
+ FilteringConfiguration.setAutoInstallEnabled(enable, mBrowserContextHandle);
+ }
+
+ @UiThread
+ public boolean isAutoInstallEnabled() {
+ return FilteringConfiguration.isAutoInstallEnabled(mBrowserContextHandle);
+ }
+
+ @UiThread
+ public void installSubscription(final URL url) {
+ mFilteringConfiguration.addFilterList(url);
+ }
+
+ @UiThread
+ public void uninstallSubscription(final URL url) {
+ mFilteringConfiguration.removeFilterList(url);
+ }
+
+ @UiThread
+ public List<Subscription> getInstalledSubscriptions() {
+ return (List<Subscription>)
+ (List<?>)
+ Arrays.asList(
+ AdblockControllerJni.get()
+ .getInstalledSubscriptions(mBrowserContextHandle));
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void setEnabled(boolean enabled) throws IllegalStateException {
+ mFilteringConfiguration.setEnabled(enabled);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public boolean isEnabled() throws IllegalStateException {
+ return mFilteringConfiguration.isEnabled();
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void removeFilterList(final URL url) throws IllegalStateException {
+ mFilteringConfiguration.removeFilterList(url);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public List<URL> getFilterLists() throws IllegalStateException {
+ return mFilteringConfiguration.getFilterLists();
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void addAllowedDomain(final String domain) throws IllegalStateException {
+ mFilteringConfiguration.addAllowedDomain(domain);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void removeAllowedDomain(final String domain) throws IllegalStateException {
+ mFilteringConfiguration.removeAllowedDomain(domain);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public List<String> getAllowedDomains() throws IllegalStateException {
+ return mFilteringConfiguration.getAllowedDomains();
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void addCustomFilter(final String filter) throws IllegalStateException {
+ mFilteringConfiguration.addCustomFilter(filter);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void removeCustomFilter(final String filter) throws IllegalStateException {
+ mFilteringConfiguration.removeCustomFilter(filter);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public List<String> getCustomFilters() throws IllegalStateException {
+ return mFilteringConfiguration.getCustomFilters();
+ }
+
+ public interface SubscriptionUpdateObserver
+ extends FilteringConfiguration.SubscriptionUpdateObserver {}
+
+ @UiThread
+ public void addSubscriptionUpdateObserver(final SubscriptionUpdateObserver observer) {
+ mFilteringConfiguration.addSubscriptionUpdateObserver(observer);
+ }
+
+ @UiThread
+ public void removeSubscriptionUpdateObserver(final SubscriptionUpdateObserver observer) {
+ mFilteringConfiguration.removeSubscriptionUpdateObserver(observer);
+ }
+
+ @NativeMethods
+ interface Natives {
+ Object[] getInstalledSubscriptions(BrowserContextHandle contextHandle);
+
+ Object[] getRecommendedSubscriptions();
+ }
+}
diff --git a/components/adblock/android/java/src/org/chromium/components/adblock/AdblockSwitches.java b/components/adblock/android/java/src/org/chromium/components/adblock/AdblockSwitches.java
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/java/src/org/chromium/components/adblock/AdblockSwitches.java
@@ -0,0 +1,22 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.components.adblock;
+
+public class AdblockSwitches {
+ public static final String DISABLE_EYEO_REQUEST_THROTTLING = "disable-eyeo-request-throttling";
+}
diff --git a/components/adblock/android/java/src/org/chromium/components/adblock/ContentType.java b/components/adblock/android/java/src/org/chromium/components/adblock/ContentType.java
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/java/src/org/chromium/components/adblock/ContentType.java
@@ -0,0 +1,61 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.components.adblock;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum ContentType {
+ // Note. This has to be kept in sync with c++ enum so some values
+ // are skipped
+ CONTENT_TYPE_OTHER(1 << 0),
+ CONTENT_TYPE_SCRIPT(1 << 1),
+ CONTENT_TYPE_IMAGE(1 << 2),
+ CONTENT_TYPE_STYLESHEET(1 << 3),
+ CONTENT_TYPE_OBJECT(1 << 4),
+ CONTENT_TYPE_SUBDOCUMENT(1 << 5),
+ CONTENT_TYPE_WEBSOCKET(1 << 7),
+ CONTENT_TYPE_WEBRTC(1 << 8),
+ CONTENT_TYPE_PING(1 << 10),
+ CONTENT_TYPE_XMLHTTPREQUEST(1 << 11),
+ CONTENT_TYPE_MEDIA(1 << 14),
+ CONTENT_TYPE_FONT(1 << 15);
+
+ private final int contentType;
+
+ private ContentType(int contentType) {
+ this.contentType = contentType;
+ }
+
+ private static final Map<Integer, ContentType> intToContentTypeMap =
+ new HashMap<Integer, ContentType>();
+
+ static {
+ for (ContentType type : ContentType.values()) {
+ intToContentTypeMap.put(type.contentType, type);
+ }
+ }
+
+ public static ContentType fromInt(int i) {
+ return intToContentTypeMap.get(i);
+ }
+
+ public int getValue() {
+ return contentType;
+ }
+}
diff --git a/components/adblock/android/java/src/org/chromium/components/adblock/FilteringConfiguration.java b/components/adblock/android/java/src/org/chromium/components/adblock/FilteringConfiguration.java
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/java/src/org/chromium/components/adblock/FilteringConfiguration.java
@@ -0,0 +1,424 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.components.adblock;
+
+import android.util.Log;
+import android.webkit.URLUtil;
+
+import androidx.annotation.UiThread;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.NativeMethods;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.content_public.browser.BrowserContextHandle;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @brief Represents an independent configuration of filters, filter lists, allowed domains and
+ * other settings that influence resource filtering and content blocking. Multiple Filtering
+ * Configurations can co-exist and be controlled separately. A network resource is blocked if
+ * any enabled Filtering Configuration determines it should be, through its filters. Elements on
+ * websites are hidden according to a superset of element-hiding selectors from all enabled
+ * Filtering Configurations. Lives on UI thread, not thread-safe.
+ */
+public final class FilteringConfiguration {
+ private static final String TAG = FilteringConfiguration.class.getSimpleName();
+ private static final Set<FilteringConfiguration> mConfigurations = new HashSet<>();
+
+ private final Set<ConfigurationChangeObserver> mConfigurationChangeObservers = new HashSet<>();
+ private final Set<SubscriptionUpdateObserver> mSubscriptionUpdateObservers = new HashSet<>();
+ private String mName;
+ private long mNativeController;
+
+ private FilteringConfiguration(
+ final String configuration_name, BrowserContextHandle browserContextHandle) {
+ // Make sure native libraries are ready to avoid org.chromium.base.JniException
+ LibraryLoader.getInstance().ensureInitialized();
+
+ mName = configuration_name;
+ mNativeController =
+ FilteringConfigurationJni.get()
+ .create(this, configuration_name, browserContextHandle);
+ }
+
+ private void DestroyNative() {
+ FilteringConfigurationJni.get().destroy(mNativeController);
+ mNativeController = 0;
+ }
+
+ private void ValidateConfiguration() throws IllegalStateException {
+ if (mNativeController == 0) {
+ throw new IllegalStateException("Configuration does not exist!");
+ }
+ }
+
+ public interface ConfigurationChangeObserver {
+ /** Triggered when the FilteringConfiguration becomes disabled or enabled. */
+ @UiThread
+ void onEnabledStateChanged();
+
+ /** Triggered when the collection of installed filter lists changes. */
+ @UiThread
+ void onFilterListsChanged();
+
+ /** Triggered when the set of allowed domain changes. */
+ @UiThread
+ void onAllowedDomainsChanged();
+
+ /** Triggered when the set of custom filters changes. */
+ @UiThread
+ void onCustomFiltersChanged();
+ }
+
+ public interface SubscriptionUpdateObserver {
+ @UiThread
+ void onSubscriptionDownloaded(final URL url);
+ }
+
+ @UiThread
+ public void addObserver(final ConfigurationChangeObserver observer) {
+ mConfigurationChangeObservers.add(observer);
+ }
+
+ @UiThread
+ public void removeObserver(final ConfigurationChangeObserver observer) {
+ mConfigurationChangeObservers.remove(observer);
+ }
+
+ @UiThread
+ public void addSubscriptionUpdateObserver(final SubscriptionUpdateObserver observer) {
+ mSubscriptionUpdateObservers.add(observer);
+ }
+
+ @UiThread
+ public void removeSubscriptionUpdateObserver(final SubscriptionUpdateObserver observer) {
+ mSubscriptionUpdateObservers.remove(observer);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void setEnabled(boolean enabled) throws IllegalStateException {
+ ValidateConfiguration();
+ FilteringConfigurationJni.get().setEnabled(mNativeController, enabled);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public boolean isEnabled() throws IllegalStateException {
+ ValidateConfiguration();
+ return FilteringConfigurationJni.get().isEnabled(mNativeController);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void addFilterList(final URL url) throws IllegalStateException {
+ ValidateConfiguration();
+ FilteringConfigurationJni.get().addFilterList(mNativeController, url.toString());
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void removeFilterList(final URL url) throws IllegalStateException {
+ ValidateConfiguration();
+ FilteringConfigurationJni.get().removeFilterList(mNativeController, url.toString());
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public List<URL> getFilterLists() throws IllegalStateException {
+ ValidateConfiguration();
+ List<String> filterListsStr =
+ Arrays.asList(FilteringConfigurationJni.get().getFilterLists(mNativeController));
+ List<URL> filterLists = new ArrayList<URL>();
+ for (String url : filterListsStr) {
+ try {
+ filterLists.add(new URL(url));
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "Received invalid subscription URL from C++: " + url);
+ }
+ }
+ return filterLists;
+ }
+
+ @UiThread
+ public String getAcceptableAdsUrl() {
+ ValidateConfiguration();
+ return FilteringConfigurationJni.get().getAcceptableAdsUrl();
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void addAllowedDomain(final String domain) throws IllegalStateException {
+ ValidateConfiguration();
+ String sanitizedDomain = sanitizeSite(domain);
+ if (sanitizedDomain == null) return;
+ FilteringConfigurationJni.get().addAllowedDomain(mNativeController, sanitizedDomain);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void removeAllowedDomain(final String domain) throws IllegalStateException {
+ ValidateConfiguration();
+ String sanitizedDomain = sanitizeSite(domain);
+ if (sanitizedDomain == null) return;
+ FilteringConfigurationJni.get().removeAllowedDomain(mNativeController, sanitizedDomain);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public List<String> getAllowedDomains() throws IllegalStateException {
+ ValidateConfiguration();
+ List<String> allowedDomains =
+ Arrays.asList(FilteringConfigurationJni.get().getAllowedDomains(mNativeController));
+ Collections.sort(allowedDomains);
+ return allowedDomains;
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void addCustomFilter(final String filter) throws IllegalStateException {
+ ValidateConfiguration();
+ FilteringConfigurationJni.get().addCustomFilter(mNativeController, filter);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public void removeCustomFilter(final String filter) throws IllegalStateException {
+ ValidateConfiguration();
+ FilteringConfigurationJni.get().removeCustomFilter(mNativeController, filter);
+ }
+
+ /**
+ * @throws IllegalStateException when called on removed FilteringConfiguration.
+ */
+ @UiThread
+ public List<String> getCustomFilters() throws IllegalStateException {
+ ValidateConfiguration();
+ return Arrays.asList(FilteringConfigurationJni.get().getCustomFilters(mNativeController));
+ }
+
+ @UiThread
+ public static FilteringConfiguration createConfiguration(
+ final String configuration_name, BrowserContextHandle browserContextHandle) {
+ FilteringConfiguration configuration = findConfigurationByName(configuration_name);
+ if (configuration == null) {
+ configuration = new FilteringConfiguration(configuration_name, browserContextHandle);
+ mConfigurations.add(configuration);
+ }
+ return configuration;
+ }
+
+ @UiThread
+ public static void removeConfiguration(
+ final String configuration_name, BrowserContextHandle browserContextHandle) {
+ // sync with native filtering configurations
+ getConfigurations(browserContextHandle);
+ final FilteringConfiguration configuration = findConfigurationByName(configuration_name);
+ if (configuration != null) {
+ configuration.DestroyNative();
+ mConfigurations.remove(configuration);
+ }
+ }
+
+ @UiThread
+ public static List<FilteringConfiguration> getConfigurations(
+ BrowserContextHandle browserContextHandle) {
+ // Get all existing (on C++ side) configurations, if there is no matching Java
+ // instance present in mConfigurations set then create one and add.
+ final String[] existing_configurations_names =
+ FilteringConfigurationJni.get().getConfigurations(browserContextHandle);
+ final List<FilteringConfiguration> configurations_to_return =
+ new ArrayList<FilteringConfiguration>();
+ // If mConfigurations contains configurations which are not present on the list returned
+ // from FilteringConfigurationJni.get().getConfigurations() then we need to remove them
+ // as it means that a configuration has been removed on native side (not via Java API).
+ mConfigurations.removeIf(
+ filteringConfiguration -> {
+ return !Arrays.asList(existing_configurations_names)
+ .contains(filteringConfiguration.mName);
+ });
+ for (final String configuration_name : existing_configurations_names) {
+ FilteringConfiguration configuration = findConfigurationByName(configuration_name);
+ if (configuration == null) {
+ configuration =
+ new FilteringConfiguration(configuration_name, browserContextHandle);
+ mConfigurations.add(configuration);
+ }
+ configurations_to_return.add((FilteringConfiguration) configuration);
+ }
+ Collections.sort(
+ configurations_to_return,
+ new Comparator<FilteringConfiguration>() {
+ @Override
+ public int compare(
+ final FilteringConfiguration object1,
+ final FilteringConfiguration object2) {
+ return object1.mName.compareTo(object2.mName);
+ }
+ });
+ return configurations_to_return;
+ }
+
+ @UiThread
+ private static FilteringConfiguration findConfigurationByName(final String configuration_name) {
+ for (final FilteringConfiguration configuration : mConfigurations) {
+ if (configuration.mName.equals(configuration_name)) {
+ return configuration;
+ }
+ }
+ return null;
+ }
+
+ @UiThread
+ public static void setAutoInstallEnabled(
+ boolean enable, BrowserContextHandle browserContextHandle) {
+ FilteringConfigurationJni.get().setAutoInstallEnabled(enable, browserContextHandle);
+ }
+
+ @UiThread
+ public static boolean isAutoInstallEnabled(BrowserContextHandle browserContextHandle) {
+ return FilteringConfigurationJni.get().isAutoInstallEnabled(browserContextHandle);
+ }
+
+ private String sanitizeSite(String site) {
+ // |site| is raw user input. We expect it to be either a domain or a URL.
+ try {
+ URL candidate = new URL(URLUtil.guessUrl(site));
+ return candidate.getHost();
+ } catch (java.net.MalformedURLException e) {
+ }
+ // Could not parse |site| as URL or domain.
+ return null;
+ }
+
+ @CalledByNative
+ private void enabledStateChanged() {
+ ThreadUtils.assertOnUiThread();
+ for (final ConfigurationChangeObserver observer : mConfigurationChangeObservers) {
+ observer.onEnabledStateChanged();
+ }
+ }
+
+ @CalledByNative
+ private void filterListsChanged() {
+ ThreadUtils.assertOnUiThread();
+ for (final ConfigurationChangeObserver observer : mConfigurationChangeObservers) {
+ observer.onFilterListsChanged();
+ }
+ }
+
+ @CalledByNative
+ private void allowedDomainsChanged() {
+ ThreadUtils.assertOnUiThread();
+ for (final ConfigurationChangeObserver observer : mConfigurationChangeObservers) {
+ observer.onAllowedDomainsChanged();
+ }
+ }
+
+ @CalledByNative
+ private void customFiltersChanged() {
+ ThreadUtils.assertOnUiThread();
+ for (final ConfigurationChangeObserver observer : mConfigurationChangeObservers) {
+ observer.onCustomFiltersChanged();
+ }
+ }
+
+ @CalledByNative
+ private void onSubscriptionUpdated(final String url) {
+ ThreadUtils.assertOnUiThread();
+ try {
+ URL subscriptionUrl = new URL(URLUtil.guessUrl(url));
+ for (final SubscriptionUpdateObserver observer : mSubscriptionUpdateObservers) {
+ observer.onSubscriptionDownloaded(subscriptionUrl);
+ }
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "Error parsing subscription url: " + url);
+ }
+ }
+
+ @NativeMethods
+ public interface Natives {
+ void destroy(long nativeFilteringConfigurationAndroid);
+
+ void setEnabled(long nativeFilteringConfigurationAndroid, boolean enabled);
+
+ boolean isEnabled(long nativeFilteringConfigurationAndroid);
+
+ void addAllowedDomain(long nativeFilteringConfigurationAndroid, String domain);
+
+ void removeAllowedDomain(long nativeFilteringConfigurationAndroid, String domain);
+
+ String[] getAllowedDomains(long nativeFilteringConfigurationAndroid);
+
+ void addCustomFilter(long nativeFilteringConfigurationAndroid, String filter);
+
+ void removeCustomFilter(long nativeFilteringConfigurationAndroid, String filter);
+
+ String[] getCustomFilters(long nativeFilteringConfigurationAndroid);
+
+ void addFilterList(long nativeFilteringConfigurationAndroid, String url);
+
+ void removeFilterList(long nativeFilteringConfigurationAndroid, String url);
+
+ String[] getFilterLists(long nativeFilteringConfigurationAndroid);
+
+ long create(
+ FilteringConfiguration controller,
+ final String configuration_name,
+ BrowserContextHandle contextHandle);
+
+ void setAutoInstallEnabled(boolean enable, BrowserContextHandle contextHandle);
+
+ boolean isAutoInstallEnabled(BrowserContextHandle contextHandle);
+
+ String[] getConfigurations(BrowserContextHandle contextHandle);
+
+ String getAcceptableAdsUrl();
+ }
+}
diff --git a/components/adblock/android/java/src/org/chromium/components/adblock/ResourceClassificationNotifier.java b/components/adblock/android/java/src/org/chromium/components/adblock/ResourceClassificationNotifier.java
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/java/src/org/chromium/components/adblock/ResourceClassificationNotifier.java
@@ -0,0 +1,233 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.components.adblock;
+
+import android.util.Log;
+
+import androidx.annotation.UiThread;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.NativeMethods;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.content_public.browser.BrowserContextHandle;
+import org.chromium.content_public.browser.GlobalRenderFrameHostId;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ResourceClassificationNotifier {
+ private static final String TAG = ResourceClassificationNotifier.class.getSimpleName();
+
+ private long mNativeController;
+ private static ResourceClassificationNotifier sInstance;
+
+ private final Set<ResourceFilteringObserver> mResourceFilteringObservers = new HashSet<>();
+
+ // TODO(mpawlowski) in the future, we can consider adding filter hit
+ // notifications here as well (DPD-1233)
+
+ public interface ResourceFilteringObserver {
+ /**
+ * "Request allowed" event for a request which would be blocked but there was an
+ * allowlisting filter found.
+ *
+ * <p>It should not block the UI thread for too long.
+ *
+ * @param info contains auxiliary information about the resource.
+ */
+ @UiThread
+ void onRequestAllowed(ResourceFilteringCounters.ResourceInfo info);
+
+ /**
+ * "Request blocked" event for a request which was blocked.
+ *
+ * <p>It should not block the UI thread for too long.
+ *
+ * @param info contains auxiliary information about the resource.
+ */
+ @UiThread
+ void onRequestBlocked(ResourceFilteringCounters.ResourceInfo info);
+
+ /**
+ * "Page allowed" event for an allowlisted domain (page).
+ *
+ * <p>It should not block the UI thread for too long.
+ *
+ * @param info contains auxiliary information about the resource.
+ */
+ @UiThread
+ void onPageAllowed(ResourceFilteringCounters.ResourceInfo info);
+
+ /**
+ * "Popup allowed" event for a popup which would be blocked but there was an allowlisting
+ * filter found.
+ *
+ * <p>It should not block the UI thread for too long.
+ *
+ * @param info contains auxiliary information about the resource.
+ */
+ @UiThread
+ void onPopupAllowed(ResourceFilteringCounters.ResourceInfo info);
+
+ /**
+ * "Popup blocked" event for a popup which was blocked.
+ *
+ * <p>It should not block the UI thread for too long.
+ *
+ * @param info contains auxiliary information about the resource.
+ */
+ @UiThread
+ void onPopupBlocked(ResourceFilteringCounters.ResourceInfo info);
+ }
+
+ private ResourceClassificationNotifier(BrowserContextHandle contextHandle) {
+ mNativeController = ResourceClassificationNotifierJni.get().create(this, contextHandle);
+ assert mNativeController != 0
+ : "Failed to instantiate native ResourceClassificationNotifier";
+ }
+
+ public static ResourceClassificationNotifier getInstance(BrowserContextHandle contextHandle) {
+ // Make sure native libraries are ready to avoid org.chromium.base.JniException
+ LibraryLoader.getInstance().ensureInitialized();
+ ThreadUtils.assertOnUiThread();
+ if (sInstance == null) {
+ sInstance = new ResourceClassificationNotifier(contextHandle);
+ }
+ return sInstance;
+ }
+
+ @UiThread
+ public void addResourceFilteringObserver(final ResourceFilteringObserver observer) {
+ mResourceFilteringObservers.add(observer);
+ }
+
+ @UiThread
+ public void removeResourceFilteringObserver(final ResourceFilteringObserver observer) {
+ mResourceFilteringObservers.remove(observer);
+ }
+
+ @CalledByNative
+ private void requestMatchedCallback(
+ final String requestUrl,
+ boolean wasBlocked,
+ final String[] parentFrameUrls,
+ final String subscriptionUrl,
+ final String configurationName,
+ final int contentType,
+ final int renderProcessId,
+ final int renderFrameId) {
+ ThreadUtils.assertOnUiThread();
+ final List<String> parentsList = Arrays.asList(parentFrameUrls);
+ final ResourceFilteringCounters.ResourceInfo resourceInfo =
+ new ResourceFilteringCounters.ResourceInfo(
+ requestUrl,
+ parentsList,
+ subscriptionUrl,
+ configurationName,
+ contentType,
+ new GlobalRenderFrameHostId(renderProcessId, renderFrameId));
+ Log.d(
+ TAG,
+ "eyeo: requestMatchedCallback() notifies "
+ + mResourceFilteringObservers.size()
+ + " listeners about "
+ + resourceInfo.toString()
+ + (wasBlocked ? " getting blocked" : " being allowed"));
+ for (final ResourceFilteringObserver observer : mResourceFilteringObservers) {
+ if (wasBlocked) {
+ observer.onRequestBlocked(resourceInfo);
+ } else {
+ observer.onRequestAllowed(resourceInfo);
+ }
+ }
+ }
+
+ @CalledByNative
+ private void pageAllowedCallback(
+ final String requestUrl,
+ final String subscriptionUrl,
+ final String configurationName,
+ final int renderProcessId,
+ final int renderFrameId) {
+ ThreadUtils.assertOnUiThread();
+ final ResourceFilteringCounters.ResourceInfo resourceInfo =
+ new ResourceFilteringCounters.ResourceInfo(
+ requestUrl,
+ new ArrayList(),
+ subscriptionUrl,
+ configurationName,
+ ContentType.CONTENT_TYPE_OTHER.getValue(),
+ new GlobalRenderFrameHostId(renderProcessId, renderFrameId));
+ Log.d(
+ TAG,
+ "eyeo: pageAllowedCallback() notifies "
+ + mResourceFilteringObservers.size()
+ + " listeners about "
+ + resourceInfo.toString());
+ for (final ResourceFilteringObserver observer : mResourceFilteringObservers) {
+ observer.onPageAllowed(resourceInfo);
+ }
+ }
+
+ @CalledByNative
+ private void popupMatchedCallback(
+ final String requestUrl,
+ boolean wasBlocked,
+ final String openerUrl,
+ final String subscription,
+ final String configurationName,
+ final int renderProcessId,
+ final int renderFrameId) {
+ ThreadUtils.assertOnUiThread();
+ final List<String> parentsList = Arrays.asList(openerUrl);
+ final ResourceFilteringCounters.ResourceInfo resourceInfo =
+ new ResourceFilteringCounters.ResourceInfo(
+ requestUrl,
+ parentsList,
+ subscription,
+ configurationName,
+ ContentType.CONTENT_TYPE_OTHER.getValue(),
+ new GlobalRenderFrameHostId(renderProcessId, renderFrameId));
+ Log.d(
+ TAG,
+ "eyeo: popupMatchedCallback() notifies "
+ + mResourceFilteringObservers.size()
+ + " listeners about "
+ + resourceInfo.toString()
+ + (wasBlocked ? " getting blocked" : " being allowed"));
+ for (final ResourceFilteringObserver observer : mResourceFilteringObservers) {
+ if (wasBlocked) {
+ observer.onPopupBlocked(resourceInfo);
+ } else {
+ observer.onPopupAllowed(resourceInfo);
+ }
+ }
+ }
+
+ @NativeMethods
+ public interface Natives {
+ // Create an instance of ResourceClassificationNotifier associated with the supplied
+ // profile.
+ long create(ResourceClassificationNotifier controller, BrowserContextHandle contextHandle);
+ }
+}
diff --git a/components/adblock/android/java/src/org/chromium/components/adblock/ResourceFilteringCounters.java b/components/adblock/android/java/src/org/chromium/components/adblock/ResourceFilteringCounters.java
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/java/src/org/chromium/components/adblock/ResourceFilteringCounters.java
@@ -0,0 +1,111 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.components.adblock;
+
+import org.chromium.content_public.browser.GlobalRenderFrameHostId;
+
+import java.util.List;
+
+public class ResourceFilteringCounters {
+ /** Immutable data-class containing an auxiliary information about resource event. */
+ public static class ResourceInfo {
+ // TODO: Make members private
+ final String mRequestUrl;
+ final List<String> mParentFrameUrls;
+ final String mSubscriptionUrl;
+ final String mConfigurationName;
+ final ContentType mContentType;
+ final GlobalRenderFrameHostId mMainFrameId;
+
+ ResourceInfo(
+ final String requestUrl,
+ final List<String> parentFrameUrls,
+ final String subscriptionUrl,
+ final String configurationName,
+ final int contentType,
+ final GlobalRenderFrameHostId mainFrameId) {
+ this.mRequestUrl = requestUrl;
+ this.mParentFrameUrls = parentFrameUrls;
+ this.mSubscriptionUrl = subscriptionUrl;
+ this.mConfigurationName = configurationName;
+ this.mContentType = ContentType.fromInt(contentType);
+ this.mMainFrameId = mainFrameId;
+ }
+
+ /**
+ * @return The request which was blocked or allowed.
+ */
+ public String getRequestUrl() {
+ return mRequestUrl;
+ }
+
+ /**
+ * @return The parent frames of the mRequestUrl.
+ */
+ public List<String> getParentFrameUrls() {
+ return mParentFrameUrls;
+ }
+
+ /**
+ * @return Subscription url for filter done blocking or allowing decision, empty string
+ * otherwise.
+ */
+ public String getSubscription() {
+ return mSubscriptionUrl;
+ }
+
+ /**
+ * @return Configuration name containing subscription with matched filer for blocking or
+ * allowing decision, empty string otherwise.
+ */
+ public String getConfigurationName() {
+ return mConfigurationName;
+ }
+
+ /**
+ * @return The resource content type. See enum ContentType in components/adblock/types.h
+ */
+ public ContentType getContentType() {
+ return mContentType;
+ }
+
+ /**
+ * @return The current tab id for the mRequestUrl. -1 means no tab id, likely tab closed
+ * before event arrived. Numbers start from 0.
+ */
+ public GlobalRenderFrameHostId getMainFrameId() {
+ return mMainFrameId;
+ }
+
+ @Override
+ public String toString() {
+ return "mRequestUrl: "
+ + mRequestUrl
+ + ", mParentFrameUrls: "
+ + mParentFrameUrls.toString()
+ + ", mSubscriptionUrl:"
+ + mSubscriptionUrl
+ + ", mConfigurationName:"
+ + mConfigurationName
+ + ", mContentType: "
+ + mContentType.getValue()
+ + ", mMainFrameId: "
+ + mMainFrameId.frameRoutingId();
+ }
+ }
+}
diff --git a/components/adblock/android/resource_classification_notifier_android.cc b/components/adblock/android/resource_classification_notifier_android.cc
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/resource_classification_notifier_android.cc
@@ -0,0 +1,166 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "components/adblock/android/resource_classification_notifier_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/jni_weak_ref.h"
+#include "components/adblock/content/browser/factories/resource_classification_runner_factory.h"
+#include "components/adblock/core/common/adblock_utils.h"
+#include "content/public/browser/android/browser_context_handle.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+#include "components/adblock/android/jni_headers/ResourceClassificationNotifier_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
+using base::android::ToJavaArrayOfStrings;
+
+namespace adblock {
+
+ResourceClassificationNotifierAndroid::ResourceClassificationNotifierAndroid(
+ JNIEnv* env,
+ const JavaRef<jobject>& jcontroller,
+ ResourceClassificationRunner* classification_runner)
+ : classification_runner_(classification_runner),
+ java_weak_controller_(env, jcontroller) {
+ if (classification_runner_) {
+ classification_runner_->AddObserver(this);
+ }
+}
+
+ResourceClassificationNotifierAndroid::
+ ~ResourceClassificationNotifierAndroid() {
+ if (classification_runner_) {
+ classification_runner_->RemoveObserver(this);
+ }
+}
+
+void ResourceClassificationNotifierAndroid::OnRequestMatched(
+ const GURL& url,
+ FilterMatchResult result,
+ const std::vector<GURL>& parent_frame_urls,
+ ContentType content_type,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(render_frame_host);
+ DCHECK(result == FilterMatchResult::kBlockRule ||
+ result == FilterMatchResult::kAllowRule);
+ const bool was_blocked = result == FilterMatchResult::kBlockRule;
+ DVLOG(3) << "[eyeo] Ad matched " << url << "(type: " << content_type
+ << (was_blocked ? ", blocked" : ", allowed") << ")";
+ JNIEnv* env = AttachCurrentThread();
+ auto java_controller = java_weak_controller_.get(env);
+ if (!java_controller.is_null()) {
+ ScopedJavaLocalRef<jstring> j_url =
+ ConvertUTF8ToJavaString(env, url.spec());
+ ScopedJavaLocalRef<jobjectArray> j_parents = ToJavaArrayOfStrings(
+ env, adblock::utils::ConvertURLs(parent_frame_urls));
+ ScopedJavaLocalRef<jstring> j_subscription =
+ ConvertUTF8ToJavaString(env, subscription.spec());
+ ScopedJavaLocalRef<jstring> j_configuration =
+ ConvertUTF8ToJavaString(env, configuration_name);
+ const content::GlobalRenderFrameHostId rfh_id =
+ render_frame_host->GetGlobalId();
+ Java_ResourceClassificationNotifier_requestMatchedCallback(
+ env, java_controller, j_url, was_blocked, j_parents, j_subscription,
+ j_configuration, static_cast<int>(content_type), rfh_id.child_id.GetUnsafeValue(),
+ rfh_id.frame_routing_id);
+ }
+}
+
+void ResourceClassificationNotifierAndroid::OnPageAllowed(
+ const GURL& url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(render_frame_host);
+ DVLOG(3) << "[eyeo] Page allowed " << url;
+ JNIEnv* env = AttachCurrentThread();
+ auto java_controller = java_weak_controller_.get(env);
+ if (!java_controller.is_null()) {
+ ScopedJavaLocalRef<jstring> j_url =
+ ConvertUTF8ToJavaString(env, url.spec());
+ ScopedJavaLocalRef<jstring> j_subscription =
+ ConvertUTF8ToJavaString(env, subscription.spec());
+ ScopedJavaLocalRef<jstring> j_configuration =
+ ConvertUTF8ToJavaString(env, configuration_name);
+ const content::GlobalRenderFrameHostId rfh_id =
+ render_frame_host->GetGlobalId();
+ Java_ResourceClassificationNotifier_pageAllowedCallback(
+ env, java_controller, j_url, j_subscription, j_configuration,
+ rfh_id.child_id.GetUnsafeValue(), rfh_id.frame_routing_id);
+ }
+}
+
+void ResourceClassificationNotifierAndroid::OnPopupMatched(
+ const GURL& url,
+ FilterMatchResult result,
+ const GURL& opener_url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(render_frame_host);
+ DCHECK(result == FilterMatchResult::kBlockRule ||
+ result == FilterMatchResult::kAllowRule);
+ const bool was_blocked = result == FilterMatchResult::kBlockRule;
+ DVLOG(3) << "[eyeo] Popup matched " << url
+ << (was_blocked ? ", blocked" : ", allowed");
+ JNIEnv* env = AttachCurrentThread();
+ auto java_controller = java_weak_controller_.get(env);
+ if (!java_controller.is_null()) {
+ ScopedJavaLocalRef<jstring> j_url =
+ ConvertUTF8ToJavaString(env, url.spec());
+ ScopedJavaLocalRef<jstring> j_opener =
+ ConvertUTF8ToJavaString(env, opener_url.spec());
+ ScopedJavaLocalRef<jstring> j_subscription =
+ ConvertUTF8ToJavaString(env, subscription.spec());
+ ScopedJavaLocalRef<jstring> j_configuration =
+ ConvertUTF8ToJavaString(env, configuration_name);
+ const content::GlobalRenderFrameHostId rfh_id =
+ render_frame_host->GetGlobalId();
+ Java_ResourceClassificationNotifier_popupMatchedCallback(
+ env, java_controller, j_url, was_blocked, j_opener, j_subscription,
+ j_configuration, rfh_id.child_id.GetUnsafeValue(), rfh_id.frame_routing_id);
+ }
+}
+
+} // namespace adblock
+
+static jlong JNI_ResourceClassificationNotifier_Create(
+ JNIEnv* env,
+ const JavaRef<jobject>& jcontroller,
+ const base::android::JavaRef<jobject>& jbrowser_context_handle) {
+ DCHECK(!jcontroller.is_null());
+ DCHECK(!jbrowser_context_handle.is_null());
+ return reinterpret_cast<jlong>(
+ new adblock::ResourceClassificationNotifierAndroid(
+ env, std::move(jcontroller),
+ adblock::ResourceClassificationRunnerFactory::GetForBrowserContext(
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle))));
+}
+
+DEFINE_JNI(ResourceClassificationNotifier)
diff --git a/components/adblock/android/resource_classification_notifier_android.h b/components/adblock/android/resource_classification_notifier_android.h
new file mode 100644
--- /dev/null
+++ b/components/adblock/android/resource_classification_notifier_android.h
@@ -0,0 +1,72 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMPONENTS_ADBLOCK_ANDROID_RESOURCE_CLASSIFICATION_NOTIFIER_ANDROID_H_
+#define COMPONENTS_ADBLOCK_ANDROID_RESOURCE_CLASSIFICATION_NOTIFIER_ANDROID_H_
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_weak_ref.h"
+#include "components/adblock/content/browser/resource_classification_runner.h"
+#include "content/public/browser/browser_context.h"
+
+class FilterMatchResult;
+
+namespace adblock {
+
+class ResourceClassificationNotifierAndroid
+ : public ResourceClassificationRunner::Observer {
+ public:
+ ResourceClassificationNotifierAndroid(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jcontroller,
+ ResourceClassificationRunner* classification_runner);
+ ~ResourceClassificationNotifierAndroid() override;
+
+ // ResourceClassificationRunner::Observer
+ void OnRequestMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const std::vector<GURL>& parent_frame_urls,
+ ContentType content_type,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override;
+ void OnPageAllowed(const GURL& url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override;
+ void OnPopupMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const GURL& opener_url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override;
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+ raw_ptr<ResourceClassificationRunner> classification_runner_;
+
+ // Direct reference to ResourceClassificationNotifier java class. Kept for as
+ // long as this instance of ResourceClassificationNotifierAndroid lives:
+ // until corresponding Profile gets destroyed. Destruction of Profile triggers
+ // destruction of both C++ ResourceClassificationNotifierAndroid and Java
+ // ResourceClassificationNotifier objects.
+ const JavaObjectWeakGlobalRef java_weak_controller_;
+};
+
+} // namespace adblock
+
+#endif // COMPONENTS_ADBLOCK_ANDROID_RESOURCE_CLASSIFICATION_NOTIFIER_ANDROID_H_
--