// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.privacy_sandbox;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.fragment.app.Fragment;
import org.chromium.base.Callback;
import org.chromium.base.IntentUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.supplier.OneshotSupplier;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.settings.ChromeBaseSettingsFragment;
import org.chromium.chrome.browser.settings.SettingsLauncherFactory;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.components.browser_ui.util.TraceEventVectorDrawableCompat;
/**
* Base class for PrivacySandboxSettings related Fragments. Initializes the options menu to open a
* help page about the PrivacySandbox instead of the regular help center.
*
* <p>Subclasses have to call super.onCreatePreferences(bundle, s) when overriding
* onCreatePreferences.
*/
public abstract class PrivacySandboxSettingsBaseFragment extends ChromeBaseSettingsFragment {
// Key for the argument with which the PrivacySandbox fragment will be launched. The value for
// this argument should be part of the PrivacySandboxReferrer enum, which contains all points of
// entry to the Privacy Sandbox UI.
public static final String PRIVACY_SANDBOX_REFERRER = "privacy-sandbox-referrer";
private PrivacySandboxBridge mPrivacySandboxBridge;
private PrivacySandboxHelpers.CustomTabIntentHelper mCustomTabHelper;
private OneshotSupplier<SnackbarManager> mSnackbarManagerSupplier;
private Callback<Context> mCookieSettingsLauncher;
/** Launches the right version of PrivacySandboxSettings depending on feature flags. */
public static void launchPrivacySandboxSettings(
Context context, @PrivacySandboxReferrer int referrer) {
Bundle fragmentArgs = new Bundle();
fragmentArgs.putInt(PRIVACY_SANDBOX_REFERRER, referrer);
SettingsLauncherFactory.createSettingsLauncher()
.launchSettingsActivity(
context, PrivacySandboxSettingsFragment.class, fragmentArgs);
}
@Override
public void onCreatePreferences(@Nullable Bundle bundle, @Nullable String s) {
// Enable the options menu to be able to use a custom question mark button.
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Add the custom question mark button.
menu.clear();
MenuItem help =
menu.add(Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help);
help.setIcon(
TraceEventVectorDrawableCompat.create(
getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme()));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_id_targeted_help) {
// Action for the question mark button.
openUrlInCct(PrivacySandboxSettingsFragment.HELP_CENTER_URL);
return true;
}
return false;
}
/**
* Set the necessary CCT helpers to be able to natively open links. This is needed because the
* helpers are not modularized.
*/
public void setCustomTabIntentHelper(PrivacySandboxHelpers.CustomTabIntentHelper tabHelper) {
mCustomTabHelper = tabHelper;
}
protected void openUrlInCct(String url) {
assert (mCustomTabHelper != null)
: "CCT helpers must be set on PrivacySandboxSettingsFragment before opening a "
+ "link.";
CustomTabsIntent customTabIntent =
new CustomTabsIntent.Builder().setShowTitle(true).build();
customTabIntent.intent.setData(Uri.parse(url));
Intent intent =
mCustomTabHelper.createCustomTabActivityIntent(
getContext(), customTabIntent.intent);
intent.setPackage(getContext().getPackageName());
intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
IntentUtils.addTrustedIntentExtras(intent);
IntentUtils.safeStartActivity(getContext(), intent);
}
public void setSnackbarManagerSupplier(
OneshotSupplier<SnackbarManager> snackbarManagerSupplier) {
mSnackbarManagerSupplier = snackbarManagerSupplier;
}
protected void showSnackbar(
int stringResId,
SnackbarManager.SnackbarController controller,
int type,
int identifier) {
showSnackbar(stringResId, controller, type, identifier, 0, false);
}
protected void showSnackbar(
int stringResId,
SnackbarManager.SnackbarController controller,
int type,
int identifier,
int actionStringResId,
boolean multiLine) {
var snackbar =
Snackbar.make(getResources().getString(stringResId), controller, type, identifier);
if (actionStringResId != 0) {
snackbar.setAction(getResources().getString(actionStringResId), null);
}
if (multiLine) snackbar.setSingleLine(false);
mSnackbarManagerSupplier.get().showSnackbar(snackbar);
}
protected void parseAndRecordReferrer() {
Bundle extras = getArguments();
assert (extras != null) && extras.containsKey(PRIVACY_SANDBOX_REFERRER)
: "PrivacySandboxSettingsFragment must be launched with a privacy-sandbox-referrer "
+ "fragment argument, but none was provided.";
int referrer = extras.getInt(PRIVACY_SANDBOX_REFERRER);
// Record all the referrer metrics.
RecordHistogram.recordEnumeratedHistogram(
"Settings.PrivacySandbox.PrivacySandboxReferrer",
referrer,
PrivacySandboxReferrer.COUNT);
if (referrer == PrivacySandboxReferrer.PRIVACY_SETTINGS) {
RecordUserAction.record("Settings.PrivacySandbox.OpenedFromSettingsParent");
} else if (referrer == PrivacySandboxReferrer.COOKIES_SNACKBAR) {
RecordUserAction.record("Settings.PrivacySandbox.OpenedFromCookiesPageToast");
} else if (referrer == PrivacySandboxReferrer.PAGE_INFO_AD_PRIVACY_SECTION) {
RecordUserAction.record("PageInfo.AdPersonalization.ManageInterestClicked");
}
}
protected void launchSettingsActivity(Class<? extends Fragment> fragment) {
SettingsLauncherFactory.createSettingsLauncher()
.launchSettingsActivity(getContext(), fragment);
}
@Override
public void setProfile(@NonNull Profile profile) {
super.setProfile(profile);
mPrivacySandboxBridge = new PrivacySandboxBridge(profile);
}
/**
* Return the {@link PrivacySandboxBridge} associated with the value set in {@link
* #setProfile(Profile)}.
*/
public PrivacySandboxBridge getPrivacySandboxBridge() {
assert mPrivacySandboxBridge != null
: "Attempting to use PrivacySandboxBridge prior to setProfile being called.";
return mPrivacySandboxBridge;
}
protected void launchCookieSettings() {
if (mCookieSettingsLauncher != null) {
mCookieSettingsLauncher.onResult(getContext());
}
}
public void setCookieSettingsIntentHelper(Callback<Context> cookieSettingsLauncher) {
mCookieSettingsLauncher = cookieSettingsLauncher;
}
}