1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 package org.chromium.components.page_info;
5 
6 import android.app.Dialog;
7 import android.os.Bundle;
8 import android.text.format.Formatter;
9 
10 import androidx.appcompat.app.AlertDialog;
11 import androidx.preference.Preference;
12 
13 import org.chromium.base.Callback;
14 import org.chromium.components.browser_ui.settings.ChromeImageViewPreference;
15 import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
16 import org.chromium.components.browser_ui.settings.SettingsUtils;
17 import org.chromium.components.browser_ui.site_settings.SiteSettingsPreferenceFragment;
18 import org.chromium.components.content_settings.CookieControlsStatus;
19 import org.chromium.ui.text.NoUnderlineClickableSpan;
20 import org.chromium.ui.text.SpanApplier;
21 
22 /**
23  * View showing a toggle and a description for third-party cookie blocking for a site.
24  */
25 public class PageInfoCookiesPreference extends SiteSettingsPreferenceFragment {
26     private static final String COOKIE_SUMMARY_PREFERENCE = "cookie_summary";
27     private static final String COOKIE_SWITCH_PREFERENCE = "cookie_switch";
28     private static final String COOKIE_IN_USE_PREFERENCE = "cookie_in_use";
29     private static final String CLEAR_BUTTON_PREFERENCE = "clear_button";
30 
31     private ChromeSwitchPreference mCookieSwitch;
32     private ChromeImageViewPreference mCookieInUse;
33     private Runnable mOnClearCallback;
34     private Dialog mConfirmationDialog;
35 
36     /**  Parameters to configure the cookie controls view. */
37     public static class PageInfoCookiesViewParams {
38         // Called when the toggle controlling third-party cookie blocking changes.
39         public boolean thirdPartyCookieBlockingEnabled;
40         public Callback<Boolean> onCheckedChangedCallback;
41         public Runnable onClearCallback;
42         public Runnable onCookieSettingsLinkClicked;
43         public boolean disableCookieDeletion;
44     }
45 
46     @Override
onCreatePreferences(Bundle bundle, String s)47     public void onCreatePreferences(Bundle bundle, String s) {
48         // Remove this Preference if it is restored without SiteSettingsClient.
49         if (getSiteSettingsClient() == null) {
50             getParentFragmentManager().beginTransaction().remove(this).commit();
51             return;
52         }
53         SettingsUtils.addPreferencesFromResource(this, R.xml.page_info_cookie_preference);
54         mCookieSwitch = findPreference(COOKIE_SWITCH_PREFERENCE);
55         mCookieInUse = findPreference(COOKIE_IN_USE_PREFERENCE);
56     }
57 
58     @Override
onDestroyView()59     public void onDestroyView() {
60         super.onDestroyView();
61         if (mConfirmationDialog != null) {
62             mConfirmationDialog.dismiss();
63         }
64     }
65 
setParams(PageInfoCookiesViewParams params)66     public void setParams(PageInfoCookiesViewParams params) {
67         Preference cookieSummary = findPreference(COOKIE_SUMMARY_PREFERENCE);
68         NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan(
69                 getResources(), (view) -> { params.onCookieSettingsLinkClicked.run(); });
70         cookieSummary.setSummary(
71                 SpanApplier.applySpans(getString(R.string.page_info_cookies_description),
72                         new SpanApplier.SpanInfo("<link>", "</link>", linkSpan)));
73 
74         // TODO(crbug.com/1077766): Set a ManagedPreferenceDelegate?
75         mCookieSwitch.setVisible(params.thirdPartyCookieBlockingEnabled);
76         mCookieSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
77             params.onCheckedChangedCallback.onResult((Boolean) newValue);
78             return true;
79         });
80 
81         mCookieInUse.setIcon(
82                 SettingsUtils.getTintedIcon(getContext(), R.drawable.permission_cookie));
83         if (!params.disableCookieDeletion) {
84             mCookieInUse.setImageView(
85                     R.drawable.ic_delete_white_24dp, R.string.page_info_cookies_clear, null);
86             mCookieInUse.setImageColor(R.color.default_icon_color_blue);
87             // Disabling enables passthrough of clicks to the main preference.
88             mCookieInUse.setImageViewEnabled(false);
89             mCookieInUse.setOnPreferenceClickListener(preference -> {
90                 showClearCookiesConfirmation();
91                 return true;
92             });
93         }
94 
95         mOnClearCallback = params.onClearCallback;
96     }
97 
showClearCookiesConfirmation()98     private void showClearCookiesConfirmation() {
99         mConfirmationDialog =
100                 new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog)
101                         .setTitle(R.string.page_info_cookies_clear)
102                         .setMessage(R.string.page_info_cookies_clear_confirmation)
103                         .setPositiveButton(R.string.page_info_cookies_clear_confirmation_button,
104                                 (dialog, which) -> mOnClearCallback.run())
105                         .setNegativeButton(
106                                 R.string.cancel, (dialog, which) -> mConfirmationDialog = null)
107                         .show();
108     }
109 
setCookieBlockingStatus(@ookieControlsStatus int status, boolean isEnforced)110     public void setCookieBlockingStatus(@CookieControlsStatus int status, boolean isEnforced) {
111         boolean visible = status != CookieControlsStatus.DISABLED;
112         boolean enabled = status == CookieControlsStatus.ENABLED;
113         mCookieSwitch.setVisible(visible);
114         if (visible) {
115             mCookieSwitch.setIcon(
116                     SettingsUtils.getTintedIcon(getContext(), R.drawable.ic_eye_crossed));
117             mCookieSwitch.setChecked(enabled);
118             mCookieSwitch.setEnabled(!isEnforced);
119         }
120     }
121 
setCookiesCount(int allowedCookies, int blockedCookies)122     public void setCookiesCount(int allowedCookies, int blockedCookies) {
123         mCookieSwitch.setSummary(
124                 blockedCookies > 0 ? getContext().getResources().getQuantityString(
125                         R.plurals.cookie_controls_blocked_cookies, blockedCookies, blockedCookies)
126                                    : null);
127         mCookieInUse.setTitle(getContext().getResources().getQuantityString(
128                 R.plurals.page_info_cookies_in_use, allowedCookies, allowedCookies));
129     }
130 
setStorageUsage(long storageUsage)131     public void setStorageUsage(long storageUsage) {
132         mCookieInUse.setSummary(
133                 storageUsage > 0 ? String.format(
134                         getContext().getString(R.string.origin_settings_storage_usage_brief),
135                         Formatter.formatShortFileSize(getContext(), storageUsage))
136                                  : null);
137     }
138 }
139