// 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.
#include "components/content_settings/android/cookie_controls_bridge.h"
#include <memory>
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/permissions/permissions_client.h"
#include "content/public/browser/android/browser_context_handle.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/content_settings/android/content_settings_jni_headers/CookieControlsBridge_jni.h"
namespace content_settings {
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
CookieControlsBridge::CookieControlsBridge(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jweb_contents_android,
const JavaParamRef<jobject>& joriginal_browser_context_handle)
: jobject_(obj) {
UpdateWebContents(env, jweb_contents_android,
joriginal_browser_context_handle);
}
void CookieControlsBridge::UpdateWebContents(
JNIEnv* env,
const JavaParamRef<jobject>& jweb_contents_android,
const JavaParamRef<jobject>& joriginal_browser_context_handle) {
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(jweb_contents_android);
content::BrowserContext* original_context =
content::BrowserContextFromJavaHandle(joriginal_browser_context_handle);
content::BrowserContext* context = web_contents->GetBrowserContext();
auto* permissions_client = permissions::PermissionsClient::Get();
observation_.Reset();
controller_ = std::make_unique<CookieControlsController>(
permissions_client->GetCookieSettings(context),
original_context ? permissions_client->GetCookieSettings(original_context)
: nullptr,
permissions_client->GetSettingsMap(context),
permissions_client->GetTrackingProtectionSettings(context));
observation_.Observe(controller_.get());
controller_->Update(web_contents);
}
void CookieControlsBridge::OnStatusChanged(
bool controls_visible,
bool protections_on,
CookieControlsEnforcement enforcement,
CookieBlocking3pcdStatus blocking_status,
base::Time expiration,
std::vector<TrackingProtectionFeature> features) {
// Only invoke the callback when there is a change.
if (controls_visible_ == controls_visible &&
protections_on_ == protections_on && enforcement_ == enforcement &&
expiration_ == expiration) {
return;
}
controls_visible_ = controls_visible;
protections_on_ = protections_on;
enforcement_ = enforcement;
expiration_ = expiration;
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> jfeatures = CreateTpFeaturesList(env);
for (auto& feature : features) {
CreateTpFeatureAndAddToList(env, jfeatures, feature);
}
Java_CookieControlsBridge_onStatusChanged(
env, jobject_, static_cast<bool>(controls_visible),
static_cast<bool>(protections_on), static_cast<int>(enforcement_),
static_cast<int>(blocking_status),
expiration.InMillisecondsSinceUnixEpoch(), jfeatures);
}
void CookieControlsBridge::OnCookieControlsIconStatusChanged(
bool icon_visible,
bool protections_on,
CookieBlocking3pcdStatus blocking_status,
bool should_highlight) {
// This function's main use is for web's User Bypass icon, which
// does not observe `OnStatusChanged`. Since the Clank icon does
// observe `OnStatusChanged`, the only variable we need to pass
// on from this function is `should_highlight`.
JNIEnv* env = base::android::AttachCurrentThread();
Java_CookieControlsBridge_onHighlightCookieControl(
env, jobject_, static_cast<bool>(should_highlight));
}
void CookieControlsBridge::OnReloadThresholdExceeded() {
JNIEnv* env = base::android::AttachCurrentThread();
Java_CookieControlsBridge_onHighlightPwaCookieControl(env, jobject_);
}
void CookieControlsBridge::SetThirdPartyCookieBlockingEnabledForSite(
JNIEnv* env,
bool block_cookies) {
controller_->OnCookieBlockingEnabledForSite(block_cookies);
}
void CookieControlsBridge::OnUiClosing(JNIEnv* env) {
controller_->OnUiClosing();
}
void CookieControlsBridge::OnEntryPointAnimated(JNIEnv* env) {
controller_->OnEntryPointAnimated();
}
// static
ScopedJavaLocalRef<jobject> CookieControlsBridge::CreateTpFeaturesList(
JNIEnv* env) {
return Java_CookieControlsBridge_createTpFeatureList(env);
}
// static
void CookieControlsBridge::CreateTpFeatureAndAddToList(
JNIEnv* env,
base::android::ScopedJavaLocalRef<jobject> jfeatures,
TrackingProtectionFeature feature) {
Java_CookieControlsBridge_createTpFeatureAndAddToList(
env, jfeatures, static_cast<int>(feature.feature_type),
static_cast<int>(feature.enforcement), static_cast<int>(feature.status));
}
CookieControlsBridge::~CookieControlsBridge() = default;
void CookieControlsBridge::Destroy(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
delete this;
}
jboolean JNI_CookieControlsBridge_IsCookieControlsEnabled(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle) {
content::BrowserContext* context =
content::BrowserContextFromJavaHandle(jbrowser_context_handle);
return permissions::PermissionsClient::Get()
->GetCookieSettings(context)
->ShouldBlockThirdPartyCookies();
}
static jlong JNI_CookieControlsBridge_Init(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jweb_contents_android,
const JavaParamRef<jobject>& joriginal_browser_context_handle) {
return reinterpret_cast<intptr_t>(new CookieControlsBridge(
env, obj, jweb_contents_android, joriginal_browser_context_handle));
}
} // namespace content_settings