Commit 3b5fe53e authored by Christian Dullweber's avatar Christian Dullweber Committed by Commit Bot

Use shared state for ClearBrowsingDataPrefences

When the ClearBrowsingDataDialog is opened, a CBDPreferences is
created for each of the tabs. Each preference queries for information
about browsing history and fetches important sites. As these are
non-trivial operations, a class is introduced to only request both
infos once and share them between preferences.

Bug: 804839
Change-Id: I8495bc2e2ebeaeb8640d9d0775f701911d0045c8
Reviewed-on: https://chromium-review.googlesource.com/883783
Commit-Queue: Christian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Reviewed-by: default avatarDaniel Murphy <dmurph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#532377}
parent cbf8fac0
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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.preferences.privacy;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.ChromeFeatureList;
import java.util.Arrays;
/**
* Requests information about important sites and other forms of browsing data.
*/
public class ClearBrowsingDataFetcher
implements BrowsingDataBridge.ImportantSitesCallback,
BrowsingDataBridge.OtherFormsOfBrowsingHistoryListener {
// This is a constant on the C++ side.
private int mMaxImportantSites;
// This is the sorted list of important registerable domains. If null, then we haven't finished
// fetching them yet.
private String[] mSortedImportantDomains;
// These are the reasons the above domains were chosen as important.
private int[] mSortedImportantDomainReasons;
// These are full url examples of the domains above. We use them for favicons.
private String[] mSortedExampleOrigins;
// Whether the dialog about other forms of browsing history should be shown.
private boolean mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled;
ClearBrowsingDataFetcher() {
mMaxImportantSites = BrowsingDataBridge.getMaxImportantSites();
}
/**
* Fetch important sites if the feature is enabled.
*/
public void fetchImportantSites() {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.IMPORTANT_SITES_IN_CBD)) {
BrowsingDataBridge.fetchImportantSites(this);
}
}
/**
* Request information about other forms of browsing history if the history dialog hasn't been
* shown yet.
*/
public void requestInfoAboutOtherFormsOfBrowsingHistory() {
if (!OtherFormsOfHistoryDialogFragment.wasDialogShown())
BrowsingDataBridge.getInstance().requestInfoAboutOtherFormsOfBrowsingHistory(this);
}
/**
* @return The maximum number of important sites to show.
*/
public int getMaxImportantSites() {
return mMaxImportantSites;
}
/**
* @return Get a sorted list of important registerable domains. If null, then we haven't
* finished fetching them yet.
*/
public String[] getSortedImportantDomains() {
return mSortedImportantDomains;
}
/**
* @return The reasons the above domains were chosen as important.
*/
public int[] getSortedImportantDomainReasons() {
return mSortedImportantDomainReasons;
}
/**
* @return Full url examples of the domains above. We use them for favicons.
*/
public String[] getSortedExampleOrigins() {
return mSortedExampleOrigins;
}
/**
* @return Whether the dialog about other forms of browsing history should be shown.
*/
public boolean isDialogAboutOtherFormsOfBrowsingHistoryEnabled() {
return mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled;
}
@Override
public void onImportantRegisterableDomainsReady(String[] domains, String[] exampleOrigins,
int[] importantReasons, boolean dialogDisabled) {
if (domains == null || dialogDisabled) return;
// mMaxImportantSites is a constant on the C++ side. While 0 is valid, use 1 as the minimum
// because histogram code assumes a min >= 1; the underflow bucket will record the 0s.
RecordHistogram.recordLinearCountHistogram("History.ClearBrowsingData.NumImportant",
domains.length, 1, mMaxImportantSites + 1, mMaxImportantSites + 1);
mSortedImportantDomains = Arrays.copyOf(domains, domains.length);
mSortedImportantDomainReasons = Arrays.copyOf(importantReasons, importantReasons.length);
mSortedExampleOrigins = Arrays.copyOf(exampleOrigins, exampleOrigins.length);
}
@Override
public void enableDialogAboutOtherFormsOfBrowsingHistory() {
mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled = true;
}
}
......@@ -49,9 +49,7 @@ import java.util.concurrent.TimeUnit;
* from which to clear data.
*/
public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
implements BrowsingDataBridge.ImportantSitesCallback,
BrowsingDataBridge.OnClearBrowsingDataListener,
BrowsingDataBridge.OtherFormsOfBrowsingHistoryListener,
implements BrowsingDataBridge.OnClearBrowsingDataListener,
Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
/**
* Represents a single item in the dialog.
......@@ -260,26 +258,30 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
}
private OtherFormsOfHistoryDialogFragment mDialogAboutOtherFormsOfBrowsingHistory;
private boolean mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled;
private ProgressDialog mProgressDialog;
private Item[] mItems;
private ClearBrowsingDataFetcher mFetcher;
// This is a constant on the C++ side.
private int mMaxImportantSites;
// This is the sorted list of important registerable domains. If null, then we haven't finished
// fetching them yet.
private String[] mSortedImportantDomains;
// These are the reasons the above domains were chosen as important.
private int[] mSortedImportantDomainReasons;
// These are full url examples of the domains above. We use them for favicons.
private String[] mSortedExampleOrigins;
// This is the dialog we show to the user that lets them 'uncheck' (or exclude) the above
// important domains from being cleared.
private ConfirmImportantSitesDialogFragment mConfirmImportantSitesDialog;
// Time in ms, when the dialog was created.
private long mDialogOpened;
/**
* @param fetcher A ClearBrowsingDataFetcher.
*/
public void setClearBrowsingDataFetcher(ClearBrowsingDataFetcher fetcher) {
mFetcher = fetcher;
}
@VisibleForTesting
public ClearBrowsingDataFetcher getClearBrowsingDataFetcher() {
return mFetcher;
}
/**
* @return The currently selected DialogOptions.
*/
......@@ -403,7 +405,7 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
// this preference screen.
if (MultiWindowUtils.isActivityVisible(getActivity())
&& getSelectedOptions().contains(DialogOption.CLEAR_HISTORY)
&& mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled
&& mFetcher.isDialogAboutOtherFormsOfBrowsingHistoryEnabled()
&& !OtherFormsOfHistoryDialogFragment.wasDialogShown()) {
mDialogAboutOtherFormsOfBrowsingHistory = new OtherFormsOfHistoryDialogFragment();
mDialogAboutOtherFormsOfBrowsingHistory.show(getActivity());
......@@ -432,8 +434,8 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
&& !selectedOptions.contains(DialogOption.CLEAR_COOKIES_AND_SITE_DATA)) {
return false;
}
boolean haveImportantSites =
mSortedImportantDomains != null && mSortedImportantDomains.length != 0;
boolean haveImportantSites = mFetcher.getSortedImportantDomains() != null
&& mFetcher.getSortedImportantDomains().length != 0;
RecordHistogram.recordBooleanHistogram(
"History.ClearBrowsingData.ImportantDialogShown", haveImportantSites);
return haveImportantSites;
......@@ -499,9 +501,6 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
super.onCreate(savedInstanceState);
mDialogOpened = SystemClock.elapsedRealtime();
mMaxImportantSites = BrowsingDataBridge.getMaxImportantSites();
if (!OtherFormsOfHistoryDialogFragment.wasDialogShown())
BrowsingDataBridge.getInstance().requestInfoAboutOtherFormsOfBrowsingHistory(this);
getActivity().setTitle(R.string.clear_browsing_data_title);
PreferenceUtils.addPreferencesFromResource(this, getPreferenceXmlId());
DialogOption[] options = getDialogOptions();
......@@ -553,10 +552,6 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
assert spinnerOptionIndex != -1;
spinner.setOptions(spinnerOptions, spinnerOptionIndex);
spinner.setOnPreferenceChangeListener(this);
if (ChromeFeatureList.isEnabled(ChromeFeatureList.IMPORTANT_SITES_IN_CBD)) {
BrowsingDataBridge.fetchImportantSites(this);
}
}
@Override
......@@ -618,19 +613,13 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
*/
private void showImportantDialogThenClear() {
mConfirmImportantSitesDialog = ConfirmImportantSitesDialogFragment.newInstance(
mSortedImportantDomains, mSortedImportantDomainReasons, mSortedExampleOrigins);
mFetcher.getSortedImportantDomains(), mFetcher.getSortedImportantDomainReasons(),
mFetcher.getSortedExampleOrigins());
mConfirmImportantSitesDialog.setTargetFragment(this, IMPORTANT_SITES_DIALOG_CODE);
mConfirmImportantSitesDialog.show(
getFragmentManager(), ConfirmImportantSitesDialogFragment.FRAGMENT_TAG);
}
@Override
public void enableDialogAboutOtherFormsOfBrowsingHistory() {
if (getActivity() == null) return;
mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled = true;
}
/**
* Used only to access the dialog about other forms of browsing history from tests.
*/
......@@ -639,19 +628,6 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
return mDialogAboutOtherFormsOfBrowsingHistory;
}
@Override
public void onImportantRegisterableDomainsReady(String[] domains, String[] exampleOrigins,
int[] importantReasons, boolean dialogDisabled) {
if (domains == null || dialogDisabled) return;
// mMaxImportantSites is a constant on the C++ side. While 0 is valid, use 1 as the minimum
// because histogram code assumes a min >= 1; the underflow bucket will record the 0s.
RecordHistogram.recordLinearCountHistogram("History.ClearBrowsingData.NumImportant",
domains.length, 1, mMaxImportantSites + 1, mMaxImportantSites + 1);
mSortedImportantDomains = Arrays.copyOf(domains, domains.length);
mSortedImportantDomainReasons = Arrays.copyOf(importantReasons, importantReasons.length);
mSortedExampleOrigins = Arrays.copyOf(exampleOrigins, exampleOrigins.length);
}
/**
* This is the callback for the important domain dialog. We should only clear if we get the
* positive button response.
......@@ -668,26 +644,26 @@ public abstract class ClearBrowsingDataPreferences extends PreferenceFragment
ConfirmImportantSitesDialogFragment.IGNORED_DOMAINS_TAG);
int[] ignoredDomainReasons = data.getIntArrayExtra(
ConfirmImportantSitesDialogFragment.IGNORED_DOMAIN_REASONS_TAG);
if (deselectedDomains != null && mSortedImportantDomains != null) {
if (deselectedDomains != null && mFetcher.getSortedImportantDomains() != null) {
// mMaxImportantSites is a constant on the C++ side.
RecordHistogram.recordCustomCountHistogram(
"History.ClearBrowsingData.ImportantDeselectedNum",
deselectedDomains.length, 1, mMaxImportantSites + 1,
mMaxImportantSites + 1);
deselectedDomains.length, 1, mFetcher.getMaxImportantSites() + 1,
mFetcher.getMaxImportantSites() + 1);
RecordHistogram.recordCustomCountHistogram(
"History.ClearBrowsingData.ImportantIgnoredNum", ignoredDomains.length, 1,
mMaxImportantSites + 1, mMaxImportantSites + 1);
mFetcher.getMaxImportantSites() + 1, mFetcher.getMaxImportantSites() + 1);
// We put our max at 20 instead of 100 to reduce the number of empty buckets (as
// our maximum denominator is 5).
RecordHistogram.recordEnumeratedHistogram(
"History.ClearBrowsingData.ImportantDeselectedPercent",
deselectedDomains.length * IMPORTANT_SITES_PERCENTAGE_BUCKET_COUNT
/ mSortedImportantDomains.length,
/ mFetcher.getSortedImportantDomains().length,
IMPORTANT_SITES_PERCENTAGE_BUCKET_COUNT + 1);
RecordHistogram.recordEnumeratedHistogram(
"History.ClearBrowsingData.ImportantIgnoredPercent",
ignoredDomains.length * IMPORTANT_SITES_PERCENTAGE_BUCKET_COUNT
/ mSortedImportantDomains.length,
/ mFetcher.getSortedImportantDomains().length,
IMPORTANT_SITES_PERCENTAGE_BUCKET_COUNT + 1);
}
clearBrowsingData(getSelectedOptions(), deselectedDomains, deselectedDomainReasons,
......
......@@ -64,10 +64,14 @@ public class ClearBrowsingDataTabsFragment extends Fragment {
// Inflate the layout for this fragment.
View view = inflater.inflate(R.layout.clear_browsing_data_tabs, container, false);
ClearBrowsingDataFetcher fetcher = new ClearBrowsingDataFetcher();
fetcher.fetchImportantSites();
fetcher.requestInfoAboutOtherFormsOfBrowsingHistory();
// Get the ViewPager and set its PagerAdapter so that it can display items.
ViewPager viewPager = (ViewPager) view.findViewById(R.id.clear_browsing_data_viewpager);
viewPager.setAdapter(
new ClearBrowsingDataPagerAdapter(getFragmentManager(), getActivity()));
new ClearBrowsingDataPagerAdapter(fetcher, getFragmentManager(), getActivity()));
// Give the TabLayout the ViewPager.
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.clear_browsing_data_tabs);
......@@ -88,10 +92,13 @@ public class ClearBrowsingDataTabsFragment extends Fragment {
}
private static class ClearBrowsingDataPagerAdapter extends FragmentPagerAdapter {
private final ClearBrowsingDataFetcher mFetcher;
private final Context mContext;
ClearBrowsingDataPagerAdapter(FragmentManager fm, Context context) {
ClearBrowsingDataPagerAdapter(
ClearBrowsingDataFetcher fetcher, FragmentManager fm, Context context) {
super(fm);
mFetcher = fetcher;
mContext = context;
}
......@@ -103,14 +110,19 @@ public class ClearBrowsingDataTabsFragment extends Fragment {
@Override
public Fragment getItem(int position) {
position = adjustIndexForDirectionality(position);
ClearBrowsingDataPreferences fragment;
switch (position) {
case 0:
return new ClearBrowsingDataPreferencesBasic();
fragment = new ClearBrowsingDataPreferencesBasic();
break;
case 1:
return new ClearBrowsingDataPreferencesAdvanced();
fragment = new ClearBrowsingDataPreferencesAdvanced();
break;
default:
throw new RuntimeException("invalid position: " + position);
}
fragment.setClearBrowsingDataFetcher(mFetcher);
return fragment;
}
@Override
......
......@@ -996,6 +996,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java",
"java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesAdvanced.java",
"java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesBasic.java",
"java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataFetcher.java",
"java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataTabsFragment.java",
"java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java",
"java/src/org/chromium/chrome/browser/preferences/privacy/ContextualSearchPreferenceFragment.java",
......
......@@ -109,6 +109,17 @@ public class ClearBrowsingDataPreferencesTest {
clearButton.callOnClick();
}
private Preferences startPreferences() {
Preferences preferences = mActivityTestRule.startPreferences(
ClearBrowsingDataPreferencesAdvanced.class.getName());
ClearBrowsingDataFetcher fetcher = new ClearBrowsingDataFetcher();
ClearBrowsingDataPreferences fragment =
(ClearBrowsingDataPreferences) preferences.getFragmentForTest();
fragment.setClearBrowsingDataFetcher(fetcher);
ThreadUtils.runOnUiThreadBlocking(fetcher::fetchImportantSites);
return preferences;
}
/**
* Tests that web apps are cleared when the "cookies and site data" option is selected.
*/
......@@ -123,9 +134,7 @@ public class ClearBrowsingDataPreferencesTest {
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_COOKIES_AND_SITE_DATA));
final ClearBrowsingDataPreferences preferences =
(ClearBrowsingDataPreferences) mActivityTestRule
.startPreferences(ClearBrowsingDataPreferencesAdvanced.class.getName())
.getFragmentForTest();
(ClearBrowsingDataPreferences) startPreferences().getFragmentForTest();
ThreadUtils.runOnUiThreadBlocking(() -> clickClearButton(preferences));
waitForProgressToComplete(preferences);
......@@ -151,9 +160,7 @@ public class ClearBrowsingDataPreferencesTest {
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_HISTORY));
final ClearBrowsingDataPreferences preferences =
(ClearBrowsingDataPreferences) mActivityTestRule
.startPreferences(ClearBrowsingDataPreferencesAdvanced.class.getName())
.getFragmentForTest();
(ClearBrowsingDataPreferences) startPreferences().getFragmentForTest();
ThreadUtils.runOnUiThreadBlocking(() -> clickClearButton(preferences));
waitForProgressToComplete(preferences);
......@@ -178,9 +185,7 @@ public class ClearBrowsingDataPreferencesTest {
setDataTypesToClear(Arrays.asList(DialogOption.values()));
final ClearBrowsingDataPreferences preferences =
(ClearBrowsingDataPreferences) mActivityTestRule
.startPreferences(ClearBrowsingDataPreferencesAdvanced.class.getName())
.getFragmentForTest();
(ClearBrowsingDataPreferences) startPreferences().getFragmentForTest();
ThreadUtils.runOnUiThreadBlocking(() -> {
PreferenceScreen screen = preferences.getPreferenceScreen();
......@@ -222,7 +227,9 @@ public class ClearBrowsingDataPreferencesTest {
PreferenceScreen screen = fragment.getPreferenceScreen();
// Enable the dialog and click the "Clear" button.
fragment.enableDialogAboutOtherFormsOfBrowsingHistory();
((ClearBrowsingDataPreferences) mPreferences.getFragmentForTest())
.getClearBrowsingDataFetcher()
.enableDialogAboutOtherFormsOfBrowsingHistory();
clickClearButton(fragment);
}
}
......@@ -267,8 +274,7 @@ public class ClearBrowsingDataPreferencesTest {
// History is not selected. We still need to select some other datatype, otherwise the
// "Clear" button won't be enabled.
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_CACHE));
final Preferences preferences1 = mActivityTestRule.startPreferences(
ClearBrowsingDataPreferencesAdvanced.class.getName());
final Preferences preferences1 = startPreferences();
ThreadUtils.runOnUiThreadBlocking(
new OpenPreferencesEnableDialogAndClickClearRunnable(preferences1));
......@@ -278,8 +284,7 @@ public class ClearBrowsingDataPreferencesTest {
// Reopen Clear Browsing Data preferences, this time with history selected for clearing.
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_HISTORY));
final Preferences preferences2 = mActivityTestRule.startPreferences(
ClearBrowsingDataPreferencesAdvanced.class.getName());
final Preferences preferences2 = startPreferences();
ThreadUtils.runOnUiThreadBlocking(
new OpenPreferencesEnableDialogAndClickClearRunnable(preferences2));
......@@ -308,8 +313,7 @@ public class ClearBrowsingDataPreferencesTest {
// Reopen Clear Browsing Data preferences and clear history once again.
setDataTypesToClear(Arrays.asList(DialogOption.CLEAR_HISTORY));
final Preferences preferences3 = mActivityTestRule.startPreferences(
ClearBrowsingDataPreferencesAdvanced.class.getName());
final Preferences preferences3 = startPreferences();
ThreadUtils.runOnUiThreadBlocking(
new OpenPreferencesEnableDialogAndClickClearRunnable(preferences3));
......@@ -398,9 +402,7 @@ public class ClearBrowsingDataPreferencesTest {
"true", mActivityTestRule.runJavaScriptCodeInCurrentTab("hasAllStorage()"));
ClearBrowsingDataPreferences preferences =
(ClearBrowsingDataPreferences) mActivityTestRule
.startPreferences(ClearBrowsingDataPreferencesAdvanced.class.getName())
.getFragmentForTest();
(ClearBrowsingDataPreferences) startPreferences().getFragmentForTest();
// Clear in root preference.
ThreadUtils.runOnUiThreadBlocking(getPressClearRunnable(preferences));
......@@ -447,8 +449,7 @@ public class ClearBrowsingDataPreferencesTest {
Assert.assertEquals(
"true", mActivityTestRule.runJavaScriptCodeInCurrentTab("hasAllStorage()"));
Preferences preferences = mActivityTestRule.startPreferences(
ClearBrowsingDataPreferencesAdvanced.class.getName());
Preferences preferences = startPreferences();
ClearBrowsingDataPreferences fragment =
(ClearBrowsingDataPreferences) preferences.getFragmentForTest();
ThreadUtils.runOnUiThreadBlocking(getPressClearRunnable(fragment));
......@@ -493,8 +494,7 @@ public class ClearBrowsingDataPreferencesTest {
Assert.assertEquals(
"true", mActivityTestRule.runJavaScriptCodeInCurrentTab("hasAllStorage()"));
final Preferences preferences = mActivityTestRule.startPreferences(
ClearBrowsingDataPreferencesAdvanced.class.getName());
final Preferences preferences = startPreferences();
final ClearBrowsingDataPreferences fragment =
(ClearBrowsingDataPreferences) preferences.getFragmentForTest();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment