Skip to content

Commit

Permalink
[EoC] Contextual suggestions opt out
Browse files Browse the repository at this point in the history
Add an item in settings to turn on/off contextual suggestions.

Bug: 822953
Change-Id: I9533b6afcc21c23ee580e8d7008b6dc3ca1e74d3
Reviewed-on: https://chromium-review.googlesource.com/1006232
Commit-Queue: Becky Zhou <huayinz@chromium.org>
Reviewed-by: Theresa <twellington@chromium.org>
Reviewed-by: Matthew Jones <mdjones@chromium.org>
Reviewed-by: Bernhard Bauer <bauerb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550465}
  • Loading branch information
Becky Zhou authored and Commit Bot committed Apr 13, 2018
1 parent 16ad333 commit 5ea1b5b
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 29 deletions.
22 changes: 22 additions & 0 deletions chrome/android/java/res/xml/contextual_suggestions_preferences.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->

<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:chrome="http://schemas.android.com/apk/res-auto">

<org.chromium.chrome.browser.preferences.ChromeSwitchPreference
android:key="contextual_suggestions_switch"
android:summaryOn="@string/text_on"
android:summaryOff="@string/text_off"
chrome:drawDivider="true" />

<org.chromium.chrome.browser.preferences.TextMessagePreference
android:title="@string/contextual_suggestions_description" />

<org.chromium.chrome.browser.preferences.TextMessagePreference
android:key="contextual_suggestions_message" />

</PreferenceScreen>
23 changes: 14 additions & 9 deletions chrome/android/java/res/xml/main_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,50 +35,55 @@
android:key="notifications"
android:order="5"
android:title="@string/prefs_notifications"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.ContextualSuggestionsPreference"
android:key="contextual_suggestions"
android:order="6"
android:title="@string/prefs_contextual_suggestions"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.HomepagePreferences"
android:key="homepage"
android:order="6"
android:order="7"
android:title="@string/options_homepage_title"/>

<PreferenceCategory
android:key="advanced_section"
android:order="7"
android:order="8"
android:title="@string/prefs_section_advanced"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.privacy.PrivacyPreferences"
android:key="privacy"
android:order="8"
android:order="9"
android:title="@string/prefs_privacy"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.AccessibilityPreferences"
android:key="accessibility"
android:order="9"
android:order="10"
android:title="@string/prefs_accessibility"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.website.SiteSettingsPreferences"
android:key="content_settings"
android:order="10"
android:order="11"
android:title="@string/prefs_site_settings"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.languages.LanguagesPreferences"
android:key="languages"
android:order="11"
android:order="12"
android:title="@string/prefs_languages"/>
<org.chromium.chrome.browser.preferences.ChromeBasePreference
android:fragment="org.chromium.chrome.browser.preferences.datareduction.DataReductionPreferences"
android:key="data_reduction"
android:order="12"
android:order="13"
android:title="@string/data_reduction_title"/>
<org.chromium.chrome.browser.preferences.ChromeBasePreference
android:fragment="org.chromium.chrome.browser.preferences.download.DownloadPreferences"
android:key="downloads"
android:order="13"
android:order="14"
android:title="@string/menu_downloads"/>
<Preference
android:fragment="org.chromium.chrome.browser.preferences.AboutChromePreferences"
android:key="about_chrome"
android:order="14"
android:order="15"
android:title="@string/prefs_about_chrome"/>

</PreferenceScreen>
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* Provides access to contextual suggestions.
*/
@JNINamespace("contextual_suggestions")
class ContextualSuggestionsBridge {
public class ContextualSuggestionsBridge {
private long mNativeContextualSuggestionsBridge;

/** Result of fetching contextual suggestions. */
Expand Down Expand Up @@ -56,7 +56,7 @@ public List<ContextualSuggestionsCluster> getClusters() {
/**
* @return Whether the current profile is enterprise policy managed.
*/
static boolean isEnterprisePolicyManaged() {
public static boolean isEnterprisePolicyManaged() {
return nativeIsEnterprisePolicyManaged();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ public void onEnabledStateChanged(boolean enabled) {
}
}

@Override
public void onSettingsStateChanged(boolean enabled) {}

@Override
public void requestSuggestions(String url) {
mCurrentRequestUrl = url;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
package org.chromium.chrome.browser.contextual_suggestions;

import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.preferences.PrefChangeRegistrar;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.search_engines.TemplateUrlService;
import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
import org.chromium.chrome.browser.signin.SigninManager;
Expand All @@ -19,22 +22,30 @@
* A monitor that is responsible for detecting changes to conditions required for contextual
* suggestions to be enabled. Alerts its {@link Observer} when state changes.
*/
public class EnabledStateMonitor
implements SyncStateChangedListener, SignInStateObserver, TemplateUrlServiceObserver {
public class EnabledStateMonitor implements SyncStateChangedListener, SignInStateObserver,
TemplateUrlServiceObserver,
PrefChangeRegistrar.PrefObserver {
/** An observer to be notified of enabled state changes. **/
interface Observer {
public interface Observer {
void onEnabledStateChanged(boolean enabled);
void onSettingsStateChanged(boolean enabled);
}

@VisibleForTesting
protected Observer mObserver;
private PrefChangeRegistrar mPrefChangeRegistrar;

/** Whether contextual suggestions are enabled. */
private boolean mEnabled;

/** Whether the user settings for contextual suggestions are enabled. */
private boolean mSettingsEnabled;

/**
* Construct a new {@link EnabledStateMonitor}.
* @param observer The {@link Observer} to be notified of changes to enabled state.
*/
EnabledStateMonitor(Observer observer) {
public EnabledStateMonitor(Observer observer) {
mObserver = observer;
init();
}
Expand All @@ -46,19 +57,49 @@ interface Observer {
*/
@VisibleForTesting
protected void init() {
mPrefChangeRegistrar = new PrefChangeRegistrar();
mPrefChangeRegistrar.addObserver(Pref.CONTEXTUAL_SUGGESTIONS_ENABLED, this);
ProfileSyncService.get().addSyncStateChangedListener(this);
SigninManager.get().addSignInStateObserver(this);
TemplateUrlService.getInstance().addObserver(this);
updateEnabledState();
}

/** Destroys the EnabledStateMonitor. */
void destroy() {
public void destroy() {
mPrefChangeRegistrar.destroy();
ProfileSyncService.get().removeSyncStateChangedListener(this);
SigninManager.get().removeSignInStateObserver(this);
TemplateUrlService.getInstance().removeObserver(this);
}

/** @return Whether the user settings for contextual suggestions should be shown. */
public static boolean shouldShowSettings() {
return TemplateUrlService.getInstance().isDefaultSearchEngineGoogle()
&& !AccessibilityUtil.isAccessibilityEnabled()
&& !ContextualSuggestionsBridge.isEnterprisePolicyManaged();
}

/** @return Whether the settings state is currently enabled. */
public static boolean getSettingsEnabled() {
ProfileSyncService service = ProfileSyncService.get();

boolean isUploadToGoogleActive =
service.getUploadToGoogleState(ModelType.HISTORY_DELETE_DIRECTIVES)
== UploadState.ACTIVE;
boolean isGoogleDSE = TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
boolean isAccessibilityEnabled = AccessibilityUtil.isAccessibilityEnabled();

return isUploadToGoogleActive && isGoogleDSE && !isAccessibilityEnabled
&& !ContextualSuggestionsBridge.isEnterprisePolicyManaged();
}

/** @return Whether the state is currently enabled. */
public static boolean getEnabledState() {
return getSettingsEnabled()
&& PrefServiceBridge.getInstance().getBoolean(Pref.CONTEXTUAL_SUGGESTIONS_ENABLED);
}

/** Called when accessibility mode changes. */
void onAccessibilityModeChanged() {
updateEnabledState();
Expand All @@ -84,25 +125,25 @@ public void onTemplateURLServiceChanged() {
updateEnabledState();
}

@Override
public void onPreferenceChange() {
updateEnabledState();
}

/**
* Updates whether contextual suggestions are enabled. Notifies the observer if the
* enabled state has changed.
*/
private void updateEnabledState() {
boolean previousSettingsState = mSettingsEnabled;
boolean previousState = mEnabled;

ProfileSyncService service = ProfileSyncService.get();

boolean isUploadToGoogleActive =
service.getUploadToGoogleState(ModelType.HISTORY_DELETE_DIRECTIVES)
== UploadState.ACTIVE;
boolean isGoogleDSE = TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
boolean isAccessibilityEnabled = AccessibilityUtil.isAccessibilityEnabled();

mEnabled = isUploadToGoogleActive && isGoogleDSE && !isAccessibilityEnabled
&& !ContextualSuggestionsBridge.isEnterprisePolicyManaged();
mSettingsEnabled = getSettingsEnabled();
mEnabled = getEnabledState();

// TODO(twellington): Add run-time check for opt-out state.
if (mSettingsEnabled != previousSettingsState) {
mObserver.onSettingsStateChanged(mSettingsEnabled);
}

if (mEnabled != previousState) mObserver.onEnabledStateChanged(mEnabled);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// 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;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.annotation.Nullable;
import android.text.SpannableString;
import android.view.View;

import org.chromium.chrome.R;
import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsBridge;
import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitor;
import org.chromium.chrome.browser.signin.AccountSigninActivity;
import org.chromium.chrome.browser.signin.SigninAccessPoint;
import org.chromium.chrome.browser.sync.ui.SyncCustomizationFragment;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.components.signin.ChromeSigninController;
import org.chromium.ui.text.NoUnderlineClickableSpan;
import org.chromium.ui.text.SpanApplier;

/**
* Fragment to manage the Contextual Suggestions preference and to explain to the user what it does.
*/
public class ContextualSuggestionsPreference
extends PreferenceFragment implements EnabledStateMonitor.Observer {
private static final String PREF_CONTEXTUAL_SUGGESTIONS_SWITCH =
"contextual_suggestions_switch";
private static final String PREF_CONTEXTUAL_SUGGESTIONS_MESSAGE =
"contextual_suggestions_message";

private ChromeSwitchPreference mSwitch;
private EnabledStateMonitor mEnabledStateMonitor;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PreferenceUtils.addPreferencesFromResource(this, R.xml.contextual_suggestions_preferences);
getActivity().setTitle(R.string.prefs_contextual_suggestions);

mSwitch = (ChromeSwitchPreference) findPreference(PREF_CONTEXTUAL_SUGGESTIONS_SWITCH);
mEnabledStateMonitor = new EnabledStateMonitor(this);
initialize();
}

@Override
public void onResume() {
super.onResume();
updateSwitch();
}

@Override
public void onDestroy() {
super.onDestroy();
mEnabledStateMonitor.destroy();
}

@Override
public void onEnabledStateChanged(boolean enabled) {}

@Override
public void onSettingsStateChanged(boolean enabled) {
if (mEnabledStateMonitor != null) updateSwitch();
}

/** Helper method to initialize the switch preference and the message preference. */
private void initialize() {
final TextMessagePreference message =
(TextMessagePreference) findPreference(PREF_CONTEXTUAL_SUGGESTIONS_MESSAGE);
final SpannableString spannable = SpanApplier.applySpans(
getResources().getString(R.string.contextual_suggestions_message),
new SpanApplier.SpanInfo("<link>", "</link>", new NoUnderlineClickableSpan() {
@Override
public void onClick(View widget) {
Context context = getActivity();
if (ChromeSigninController.get().isSignedIn()) {
Intent intent = PreferencesLauncher.createIntentForSettingsPage(
context, SyncCustomizationFragment.class.getName());
IntentUtils.safeStartActivity(context, intent);
} else {
startActivity(AccountSigninActivity.createIntentForDefaultSigninFlow(
context, SigninAccessPoint.SETTINGS, false));
}
}
}));
message.setTitle(spannable);

updateSwitch();
mSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
PrefServiceBridge.getInstance().setBoolean(
Pref.CONTEXTUAL_SUGGESTIONS_ENABLED, (boolean) newValue);
return true;
});
mSwitch.setManagedPreferenceDelegate(new ManagedPreferenceDelegate() {
@Override
public boolean isPreferenceControlledByPolicy(Preference preference) {
return ContextualSuggestionsBridge.isEnterprisePolicyManaged();
}
});
}

/** Helper method to update the enabled state of the switch. */
private void updateSwitch() {
mSwitch.setEnabled(EnabledStateMonitor.getSettingsEnabled());
mSwitch.setChecked(EnabledStateMonitor.getEnabledState());
}
}
Loading

0 comments on commit 5ea1b5b

Please sign in to comment.