chromium/chrome/android/java/src/org/chromium/chrome/browser/tracing/settings/TracingCategoriesSettings.java

// Copyright 2018 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.tracing.settings;

import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;

import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;

import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.browser.tracing.TracingController;
import org.chromium.components.browser_ui.settings.ChromeBaseCheckBoxPreference;
import org.chromium.components.browser_ui.settings.SettingsPage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Settings fragment that configures chrome tracing categories of a specific type. The type is
 * passed to the fragment via an extra (EXTRA_CATEGORY_TYPE).
 */
public class TracingCategoriesSettings extends PreferenceFragmentCompat
        implements SettingsPage, Preference.OnPreferenceChangeListener {
    public static final String EXTRA_CATEGORY_TYPE = "type";

    // Non-translated strings:
    private static final String MSG_CATEGORY_SELECTION_TITLE = "Select categories";
    private static final ObservableSupplier<String> sPageTitle =
            new ObservableSupplierImpl<>(MSG_CATEGORY_SELECTION_TITLE);

    private static final String SELECT_ALL_KEY = "select-all";
    private static final String SELECT_ALL_TITLE = "Select all";

    private @TracingSettings.CategoryType int mType;
    private Set<String> mEnabledCategories;
    private List<CheckBoxPreference> mAllPreferences;
    private CheckBoxPreference mSelectAllPreference;

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        PreferenceScreen preferenceScreen =
                getPreferenceManager().createPreferenceScreen(getStyledContext());
        preferenceScreen.setOrderingAsAdded(true);

        mType = getArguments().getInt(EXTRA_CATEGORY_TYPE);
        mEnabledCategories = new HashSet<>(TracingSettings.getEnabledCategories(mType));
        mAllPreferences = new ArrayList<>();

        List<String> sortedCategories =
                new ArrayList<>(TracingController.getInstance().getKnownCategories());
        Collections.sort(sortedCategories);

        // Special preference to select all or deselect the entire list.
        mSelectAllPreference = new ChromeBaseCheckBoxPreference(getStyledContext(), null);
        mSelectAllPreference.setKey(SELECT_ALL_KEY);
        mSelectAllPreference.setTitle(SELECT_ALL_TITLE);
        mSelectAllPreference.setPersistent(false);
        mSelectAllPreference.setOnPreferenceChangeListener(this);
        preferenceScreen.addPreference(mSelectAllPreference);

        for (String category : sortedCategories) {
            if (TracingSettings.getCategoryType(category) == mType) {
                CheckBoxPreference pref = createPreference(category);
                mAllPreferences.add(pref);
                preferenceScreen.addPreference(pref);
            }
        }
        mSelectAllPreference.setChecked(mEnabledCategories.size() == mAllPreferences.size());
        setPreferenceScreen(preferenceScreen);
    }

    @Override
    public ObservableSupplier<String> getPageTitle() {
        return sPageTitle;
    }

    private CheckBoxPreference createPreference(String category) {
        CheckBoxPreference preference = new ChromeBaseCheckBoxPreference(getStyledContext(), null);
        preference.setKey(category);
        preference.setTitle(
                category.startsWith(TracingSettings.NON_DEFAULT_CATEGORY_PREFIX)
                        ? category.substring(TracingSettings.NON_DEFAULT_CATEGORY_PREFIX.length())
                        : category);
        preference.setChecked(mEnabledCategories.contains(category));
        preference.setPersistent(false); // We persist the preference value ourselves.
        preference.setOnPreferenceChangeListener(this);
        return preference;
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean value = (boolean) newValue;
        if (TextUtils.equals(SELECT_ALL_KEY, preference.getKey())) {
            setStateForAllPreferences(value);
            return true;
        }

        if (value) {
            mEnabledCategories.add(preference.getKey());
        } else {
            mEnabledCategories.remove(preference.getKey());
        }
        mSelectAllPreference.setChecked(mEnabledCategories.size() == mAllPreferences.size());
        TracingSettings.setEnabledCategories(mType, mEnabledCategories);
        return true;
    }

    private Context getStyledContext() {
        return getPreferenceManager().getContext();
    }

    private void setStateForAllPreferences(boolean enabled) {
        for (CheckBoxPreference pref : mAllPreferences) {
            pref.setChecked(enabled);
            pref.callChangeListener(pref.isChecked());
        }
    }
}