chromium/chrome/browser/privacy_sandbox/android/privacy_sandbox_bridge.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/android/callback_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/command_line.h"
#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_countries.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_countries_impl.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/privacy_sandbox/canonical_topic.h"
#include "components/privacy_sandbox/privacy_sandbox_settings.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/privacy_sandbox/android/jni_headers/PrivacySandboxBridge_jni.h"

using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;

namespace {

PrivacySandboxService* GetPrivacySandboxService(
    const base::android::JavaRef<jobject>& j_profile) {
  return PrivacySandboxServiceFactory::GetForProfile(
      Profile::FromJavaObject(j_profile));
}

std::vector<jni_zero::ScopedJavaLocalRef<jobject>> ToJavaTopicsArray(
    JNIEnv* env,
    const std::vector<privacy_sandbox::CanonicalTopic>& topics) {
  std::vector<ScopedJavaLocalRef<jobject>> j_topics;
  for (const auto& topic : topics) {
    j_topics.push_back(Java_PrivacySandboxBridge_createTopic(
        env, topic.topic_id().value(), topic.taxonomy_version(),
        ConvertUTF16ToJavaString(env, topic.GetLocalizedRepresentation()),
        ConvertUTF16ToJavaString(env, topic.GetLocalizedDescription())));
  }
  return j_topics;
}
}  // namespace

static jboolean JNI_PrivacySandboxBridge_IsPrivacySandboxRestricted(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return GetPrivacySandboxService(j_profile)->IsPrivacySandboxRestricted();
}

static jboolean JNI_PrivacySandboxBridge_IsRestrictedNoticeEnabled(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return GetPrivacySandboxService(j_profile)->IsRestrictedNoticeEnabled();
}

static std::vector<jni_zero::ScopedJavaLocalRef<jobject>>
JNI_PrivacySandboxBridge_GetCurrentTopTopics(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return ToJavaTopicsArray(
      env, GetPrivacySandboxService(j_profile)->GetCurrentTopTopics());
}

static std::vector<jni_zero::ScopedJavaLocalRef<jobject>>
JNI_PrivacySandboxBridge_GetBlockedTopics(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return ToJavaTopicsArray(
      env, GetPrivacySandboxService(j_profile)->GetBlockedTopics());
}

static std::vector<jni_zero::ScopedJavaLocalRef<jobject>>
JNI_PrivacySandboxBridge_GetFirstLevelTopics(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return ToJavaTopicsArray(
      env, GetPrivacySandboxService(j_profile)->GetFirstLevelTopics());
}

static std::vector<jni_zero::ScopedJavaLocalRef<jobject>>
JNI_PrivacySandboxBridge_GetChildTopicsCurrentlyAssigned(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jint topic_id,
    jint taxonomy_version) {
  return ToJavaTopicsArray(
      env, GetPrivacySandboxService(j_profile)->GetChildTopicsCurrentlyAssigned(
               privacy_sandbox::CanonicalTopic(browsing_topics::Topic(topic_id),
                                               taxonomy_version)));
}

static void JNI_PrivacySandboxBridge_SetTopicAllowed(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jint topic_id,
    jint taxonomy_version,
    jboolean allowed) {
  GetPrivacySandboxService(j_profile)->SetTopicAllowed(
      privacy_sandbox::CanonicalTopic(browsing_topics::Topic(topic_id),
                                      taxonomy_version),
      allowed);
}

static void JNI_PrivacySandboxBridge_GetFledgeJoiningEtldPlusOneForDisplay(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    const JavaParamRef<jobject>& j_callback) {
  GetPrivacySandboxService(j_profile)->GetFledgeJoiningEtldPlusOneForDisplay(
      base::BindOnce(
          [](const base::android::JavaRef<jobject>& j_callback,
             std::vector<std::string> strings) {
            DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
            JNIEnv* env = base::android::AttachCurrentThread();
            base::android::RunObjectCallbackAndroid(
                j_callback, base::android::ToJavaArrayOfStrings(env, strings));
          },
          base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
}

static std::vector<std::string>
JNI_PrivacySandboxBridge_GetBlockedFledgeJoiningTopFramesForDisplay(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return GetPrivacySandboxService(j_profile)
      ->GetBlockedFledgeJoiningTopFramesForDisplay();
}

static void JNI_PrivacySandboxBridge_SetFledgeJoiningAllowed(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    const JavaParamRef<jstring>& top_frame_etld_plus1,
    jboolean allowed) {
  GetPrivacySandboxService(j_profile)->SetFledgeJoiningAllowed(
      base::android::ConvertJavaStringToUTF8(top_frame_etld_plus1), allowed);
}

static jint JNI_PrivacySandboxBridge_GetRequiredPromptType(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jint surface_type) {
  // If the FRE is disabled, as it is in tests which must not be interrupted
  // with dialogs, do not attempt to show a dialog.
  const auto& command_line = *base::CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch("disable-fre"))
    return static_cast<int>(PrivacySandboxService::PromptType::kNone);

  return static_cast<int>(
      GetPrivacySandboxService(j_profile)->GetRequiredPromptType(
          static_cast<PrivacySandboxService::SurfaceType>(surface_type)));
}

static void JNI_PrivacySandboxBridge_PromptActionOccurred(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jint action,
    jint surface_type) {
  GetPrivacySandboxService(j_profile)->PromptActionOccurred(
      static_cast<PrivacySandboxService::PromptAction>(action),
      static_cast<PrivacySandboxService::SurfaceType>(surface_type));
}

static jboolean JNI_PrivacySandboxBridge_IsFirstPartySetsDataAccessEnabled(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return GetPrivacySandboxService(j_profile)
      ->IsFirstPartySetsDataAccessEnabled();
}

static jboolean JNI_PrivacySandboxBridge_IsFirstPartySetsDataAccessManaged(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  return GetPrivacySandboxService(j_profile)
      ->IsFirstPartySetsDataAccessManaged();
}

static void JNI_PrivacySandboxBridge_SetFirstPartySetsDataAccessEnabled(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jboolean enabled) {
  GetPrivacySandboxService(j_profile)->SetFirstPartySetsDataAccessEnabled(
      enabled);
}

static ScopedJavaLocalRef<jstring>
JNI_PrivacySandboxBridge_GetFirstPartySetOwner(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    const JavaParamRef<jstring>& memberOrigin) {
  auto fpsOwner = GetPrivacySandboxService(j_profile)->GetFirstPartySetOwner(
      GURL(base::android::ConvertJavaStringToUTF8(env, memberOrigin)));

  if (!fpsOwner.has_value()) {
    return nullptr;
  }

  return ConvertUTF8ToJavaString(env, fpsOwner->GetURL().host());
}

static jboolean JNI_PrivacySandboxBridge_IsPartOfManagedFirstPartySet(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    const JavaParamRef<jstring>& origin) {
  auto schemefulSite = net::SchemefulSite(
      GURL(base::android::ConvertJavaStringToUTF8(env, origin)));

  return GetPrivacySandboxService(j_profile)->IsPartOfManagedFirstPartySet(
      schemefulSite);
}

static void JNI_PrivacySandboxBridge_TopicsToggleChanged(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jboolean new_value) {
  GetPrivacySandboxService(j_profile)->TopicsToggleChanged(new_value);
}

static void
JNI_PrivacySandboxBridge_SetAllPrivacySandboxAllowedForTesting(  // IN-TEST
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile) {
  PrivacySandboxSettingsFactory::GetForProfile(
      Profile::FromJavaObject(j_profile))
      ->SetAllPrivacySandboxAllowedForTesting();  // IN-TEST
}

static void JNI_PrivacySandboxBridge_RecordActivityType(
    JNIEnv* env,
    const JavaParamRef<jobject>& j_profile,
    jint activity_type) {
  GetPrivacySandboxService(j_profile)->RecordActivityType(
      static_cast<PrivacySandboxService::PrivacySandboxStorageActivityType>(
          activity_type));
}

static jboolean JNI_PrivacySandboxBridge_IsConsentCountry(JNIEnv* env) {
  PrivacySandboxCountriesImpl instance;
  return instance.IsConsentCountry();
}