// Copyright 2015 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.SharedPreferences;
import org.chromium.base.ContextUtils;
import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.crash.MinidumpUploadService.ProcessType;
import org.chromium.chrome.browser.util.FeatureUtilities;
import java.util.Locale;
/**
* ChromePreferenceManager stores and retrieves various values in Android shared preferences.
*/
public class ChromePreferenceManager {
private static final String TAG = "preferences";
private static final String PROMOS_SKIPPED_ON_FIRST_START = "promos_skipped_on_first_start";
private static final String SIGNIN_PROMO_LAST_SHOWN = "signin_promo_last_timestamp_key";
private static final String SHOW_SIGNIN_PROMO = "show_signin_promo";
private static final String ALLOW_LOW_END_DEVICE_UI = "allow_low_end_device_ui";
private static final String PREF_WEBSITE_SETTINGS_FILTER = "website_settings_filter";
private static final String CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT =
"contextual_search_promo_open_count";
private static final String CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT =
"contextual_search_tap_triggered_promo_count";
private static final String CONTEXTUAL_SEARCH_TAP_COUNT = "contextual_search_tap_count";
private static final String CONTEXTUAL_SEARCH_PEEK_PROMO_SHOW_COUNT =
"contextual_search_peek_promo_show_count";
private static final String CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME =
"contextual_search_last_animation_time";
private static final String CONTEXTUAL_SEARCH_TAP_QUICK_ANSWER_COUNT =
"contextual_search_tap_quick_answer_count";
private static final String CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER =
"contextual_search_current_week_number";
private static final String HERB_FLAVOR_KEY = "herb_flavor";
private static final String INSTANT_APPS_KEY = "applink.app_link_enabled";
private static final String WEBAPK_RUNTIME_KEY = "webapk.runtime_enabled";
private static final String CHROME_DEFAULT_BROWSER = "applink.chrome_default_browser";
private static final String NTP_SIGNIN_PROMO_DISMISSED = "ntp.signin_promo_dismissed";
private static final String SUCCESS_UPLOAD_SUFFIX = "_crash_success_upload";
private static final String FAILURE_UPLOAD_SUFFIX = "_crash_failure_upload";
private static final int SIGNIN_PROMO_CYCLE_IN_DAYS = 120;
private static final long MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
private static ChromePreferenceManager sPrefs;
private final SharedPreferences mSharedPreferences;
private final Context mContext;
private ChromePreferenceManager(Context context) {
mContext = context.getApplicationContext();
mSharedPreferences = ContextUtils.getAppSharedPreferences();
}
/**
* Get the static instance of ChromePreferenceManager if exists else create it.
* @param context
* @return the ChromePreferenceManager singleton
*/
@SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
public static synchronized ChromePreferenceManager getInstance(Context context) {
if (sPrefs == null) {
sPrefs = new ChromePreferenceManager(context);
}
return sPrefs;
}
/**
* @return Number of times of successful crash upload.
*/
public int getCrashSuccessUploadCount(@ProcessType String process) {
// Convention to keep all the key in preference lower case.
return mSharedPreferences.getInt(successUploadKey(process), 0);
}
public void setCrashSuccessUploadCount(@ProcessType String process, int count) {
SharedPreferences.Editor sharedPreferencesEditor;
sharedPreferencesEditor = mSharedPreferences.edit();
// Convention to keep all the key in preference lower case.
sharedPreferencesEditor.putInt(successUploadKey(process), count);
sharedPreferencesEditor.apply();
}
public void incrementCrashSuccessUploadCount(@ProcessType String process) {
setCrashSuccessUploadCount(process, getCrashSuccessUploadCount(process) + 1);
}
private String successUploadKey(@ProcessType String process) {
return process.toLowerCase(Locale.US) + SUCCESS_UPLOAD_SUFFIX;
}
/**
* @return Number of times of failure crash upload after reaching the max number of tries.
*/
public int getCrashFailureUploadCount(@ProcessType String process) {
return mSharedPreferences.getInt(failureUploadKey(process), 0);
}
public void setCrashFailureUploadCount(@ProcessType String process, int count) {
SharedPreferences.Editor sharedPreferencesEditor;
sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putInt(failureUploadKey(process), count);
sharedPreferencesEditor.apply();
}
public void incrementCrashFailureUploadCount(@ProcessType String process) {
setCrashFailureUploadCount(process, getCrashFailureUploadCount(process) + 1);
}
private String failureUploadKey(@ProcessType String process) {
return process.toLowerCase(Locale.US) + FAILURE_UPLOAD_SUFFIX;
}
/**
* @return Whether the promotion for data reduction has been skipped on first invocation.
*/
public boolean getPromosSkippedOnFirstStart() {
return mSharedPreferences.getBoolean(PROMOS_SKIPPED_ON_FIRST_START, false);
}
/**
* Marks whether the data reduction promotion was skipped on first
* invocation.
* @param displayed Whether the promotion was shown.
*/
public void setPromosSkippedOnFirstStart(boolean displayed) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putBoolean(PROMOS_SKIPPED_ON_FIRST_START, displayed);
ed.apply();
}
/**
* @return The value for the website settings filter (the one that specifies
* which sites to show in the list).
*/
public String getWebsiteSettingsFilterPreference() {
return mSharedPreferences.getString(
ChromePreferenceManager.PREF_WEBSITE_SETTINGS_FILTER, "");
}
/**
* Sets the filter value for website settings (which websites to show in the list).
* @param prefValue The type to restrict the filter to.
*/
public void setWebsiteSettingsFilterPreference(String prefValue) {
SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putString(
ChromePreferenceManager.PREF_WEBSITE_SETTINGS_FILTER, prefValue);
sharedPreferencesEditor.apply();
}
/**
* This value may have been explicitly set to false when we used to keep existing low-end
* devices on the normal UI rather than the simplified UI. We want to keep the existing device
* settings. For all new low-end devices they should get the simplified UI by default.
* @return Whether low end device UI was allowed.
*/
public boolean getAllowLowEndDeviceUi() {
return mSharedPreferences.getBoolean(ALLOW_LOW_END_DEVICE_UI, true);
}
/**
* Signin promo could be shown at most once every 12 weeks. This method checks
* wheter the signin promo has already been shown in the current cycle.
* @return Whether the signin promo has been shown in the current cycle.
*/
public boolean getSigninPromoShown() {
long signinPromoLastShown = mSharedPreferences.getLong(SIGNIN_PROMO_LAST_SHOWN, 0);
long numDaysElapsed =
(System.currentTimeMillis() - signinPromoLastShown) / MILLISECONDS_IN_DAY;
return numDaysElapsed < SIGNIN_PROMO_CYCLE_IN_DAYS;
}
/**
* Sets the preference for tracking when the signin promo was last shown.
*/
public void setSigninPromoShown() {
SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putLong(SIGNIN_PROMO_LAST_SHOWN, System.currentTimeMillis());
sharedPreferencesEditor.apply();
}
/**
* @return Whether the signin promo has been marked to be shown on next startup.
*/
public boolean getShowSigninPromo() {
return mSharedPreferences.getBoolean(SHOW_SIGNIN_PROMO, false);
}
/**
* Sets the preference to indicate that the signin promo should be shown on next startup.
* @param shouldShow Whether the signin promo should be shown.
*/
public void setShowSigninPromo(boolean shouldShow) {
SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putBoolean(SHOW_SIGNIN_PROMO, shouldShow).apply();
}
/**
* @return Number of times the panel was opened with the promo visible.
*/
public int getContextualSearchPromoOpenCount() {
return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT, 0);
}
/**
* Sets the number of times the panel was opened with the promo visible.
* @param count Number of times the panel was opened with a promo visible.
*/
public void setContextualSearchPromoOpenCount(int count) {
writeInt(CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT, count);
}
/**
* @return Number of times the Peek Promo was shown.
*/
public int getContextualSearchPeekPromoShowCount() {
return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_PEEK_PROMO_SHOW_COUNT, 0);
}
/**
* Sets the number of times the Peek Promo was shown.
* @param count Number of times the Peek Promo was shown.
*/
public void setContextualSearchPeekPromoShowCount(int count) {
writeInt(CONTEXTUAL_SEARCH_PEEK_PROMO_SHOW_COUNT, count);
}
/**
* @return The last time the search provider icon was animated on tap.
*/
public long getContextualSearchLastAnimationTime() {
return mSharedPreferences.getLong(CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME, 0);
}
/**
* Sets the last time the search provider icon was animated on tap.
* @param time The last time the search provider icon was animated on tap.
*/
public void setContextualSearchLastAnimationTime(long time) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putLong(CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME, time);
ed.apply();
}
/**
* @return Number of times the promo was triggered to peek by a tap gesture, or a negative value
* if in the disabled state.
*/
public int getContextualSearchTapTriggeredPromoCount() {
return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT, 0);
}
/**
* Sets the number of times the promo was triggered to peek by a tap gesture.
* Use a negative value to record that the counter has been disabled.
* @param count Number of times the promo was triggered by a tap gesture, or a negative value
* to record that the counter has been disabled.
*/
public void setContextualSearchTapTriggeredPromoCount(int count) {
writeInt(CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT, count);
}
/**
* @return Number of tap gestures that have been received since the last time the panel was
* opened.
*/
public int getContextualSearchTapCount() {
return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_TAP_COUNT, 0);
}
/**
* Sets the number of tap gestures that have been received since the last time the panel was
* opened.
* @param count Number of taps that have been received since the last time the panel was opened.
*/
public void setContextualSearchTapCount(int count) {
writeInt(CONTEXTUAL_SEARCH_TAP_COUNT, count);
}
/**
* @return Number of Tap triggered Quick Answers (that "do answer") that have been shown since
* the last time the panel was opened.
*/
public int getContextualSearchTapQuickAnswerCount() {
return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_TAP_QUICK_ANSWER_COUNT, 0);
}
/**
* Sets the number of tap triggered Quick Answers (that "do answer") that have been shown since
* the last time the panel was opened.
* @param count Number of Tap triggered Quick Answers (that "do answer") that have been shown
* since the last time the panel was opened.
*/
public void setContextualSearchTapQuickAnswerCount(int count) {
writeInt(CONTEXTUAL_SEARCH_TAP_QUICK_ANSWER_COUNT, count);
}
/**
* @return The current week number, persisted for weekly CTR recording.
*/
public int getContextualSearchCurrentWeekNumber() {
return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER, 0);
}
/**
* Sets the current week number to persist. Used for weekly CTR recording.
* @param weekNumber The week number to store.
*/
public void setContextualSearchCurrentWeekNumber(int weekNumber) {
writeInt(CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER, weekNumber);
}
/**
* @return Which UI prototype the user is testing. This is cached from native via
* {@link FeatureUtilities#cacheHerbFlavor}.
*/
public String getCachedHerbFlavor() {
return mSharedPreferences.getString(HERB_FLAVOR_KEY, ChromeSwitches.HERB_FLAVOR_DISABLED);
}
/**
* Caches which UI prototype the user is testing.
*/
public void setCachedHerbFlavor(String flavor) {
writeString(HERB_FLAVOR_KEY, flavor);
}
/** Checks the cached value for the app link feature. */
public boolean getCachedInstantAppsEnabled() {
return mSharedPreferences.getBoolean(INSTANT_APPS_KEY, false);
}
/** Writes the cached value for whether app link is enabled. */
public void setCachedInstantAppsEnabled(boolean isEnabled) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putBoolean(INSTANT_APPS_KEY, isEnabled);
ed.apply();
}
/** Checks the cached value for the webapk feature. */
public boolean getCachedWebApkRuntimeEnabled() {
return mSharedPreferences.getBoolean(WEBAPK_RUNTIME_KEY, false);
}
/** Writes the cached value for the webapk feature is enabled. */
public void setCachedWebApkRuntimeEnabled(boolean isEnabled) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putBoolean(WEBAPK_RUNTIME_KEY, isEnabled);
ed.apply();
}
public boolean getCachedChromeDefaultBrowser() {
return mSharedPreferences.getBoolean(CHROME_DEFAULT_BROWSER, false);
}
public void setCachedChromeDefaultBrowser(boolean isDefault) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putBoolean(CHROME_DEFAULT_BROWSER, isDefault);
ed.apply();
}
/** Checks if the user dismissed the sign in promo from the new tab page. */
public boolean getNewTabPageSigninPromoDismissed() {
return mSharedPreferences.getBoolean(NTP_SIGNIN_PROMO_DISMISSED, false);
}
/** Set whether the user dismissed the sign in promo from the new tab page. */
public void setNewTabPageSigninPromoDismissed(boolean isPromoDismissed) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putBoolean(NTP_SIGNIN_PROMO_DISMISSED, isPromoDismissed);
ed.apply();
}
/**
* Writes the given int value to the named shared preference.
* @param key The name of the preference to modify.
* @param value The new value for the preference.
*/
public void writeInt(String key, int value) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putInt(key, value);
ed.apply();
}
/**
* Reads the given int value from the named shared preference.
* @param key The name of the preference to return.
* @return The value of the preference.
*/
public int readInt(String key) {
return mSharedPreferences.getInt(key, 0);
}
/**
* Writes the given String to the named shared preference.
*
* @param key The name of the preference to modify.
* @param value The new value for the preference.
*/
private void writeString(String key, String value) {
SharedPreferences.Editor ed = mSharedPreferences.edit();
ed.putString(key, value);
ed.apply();
}
}