// Copyright 2016 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.locale;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.PreferencesLauncher;
import org.chromium.chrome.browser.preferences.SearchEnginePreference;
import org.chromium.chrome.browser.snackbar.Snackbar;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
import java.lang.ref.WeakReference;
/**
* Manager for some locale specific logics.
*/
public class LocaleManager {
public static final String PREF_AUTO_SWITCH = "LocaleManager_PREF_AUTO_SWITCH";
public static final String PREF_PROMO_SHOWN = "LocaleManager_PREF_PROMO_SHOWN";
public static final String PREF_WAS_IN_SPECIAL_LOCALE = "LocaleManager_WAS_IN_SPECIAL_LOCALE";
public static final String SPECIAL_LOCALE_ID = "US";
private static final int SNACKBAR_DURATION_MS = 6000;
private static LocaleManager sInstance;
// LocaleManager is a singleton and it should not have strong reference to UI objects.
// SnackbarManager is owned by ChromeActivity and is not null as long as the activity is alive.
private WeakReference<SnackbarManager> mSnackbarManager;
private SpecialLocaleHandler mLocaleHandler;
private SnackbarController mSnackbarController = new SnackbarController() {
@Override
public void onDismissNoAction(Object actionData) { }
@Override
public void onAction(Object actionData) {
Context context = ContextUtils.getApplicationContext();
Intent intent = PreferencesLauncher.createIntentForSettingsPage(context,
SearchEnginePreference.class.getName());
context.startActivity(intent);
}
};
/**
* Starts listening to state changes of the phone.
*/
public void startObservingPhoneChanges() {
maybeAutoSwitchSearchEngine();
}
/**
* Stops listening to state changes of the phone.
*/
public void stopObservingPhoneChanges() {}
/**
* @return An instance of the {@link LocaleManager}. This should only be called on UI thread.
*/
public static LocaleManager getInstance() {
assert ThreadUtils.runningOnUiThread();
if (sInstance == null) {
sInstance = ((ChromeApplication) ContextUtils.getApplicationContext())
.createLocaleManager();
}
return sInstance;
}
/**
* Starts recording metrics in deferred startup.
*/
public void recordStartupMetrics() {}
/**
* @return Whether the Chrome instance is running in a special locale.
*/
public boolean isSpecialLocaleEnabled() {
// If there is a kill switch sent from the server, disable the feature.
if (!ChromeFeatureList.isEnabled("SpecialLocaleWrapper")) {
return false;
}
boolean inSpecialLocale = ChromeFeatureList.isEnabled("SpecialLocale");
inSpecialLocale = isReallyInSpecialLocale(inSpecialLocale);
return inSpecialLocale;
}
/**
* @return The country id of the special locale.
*/
public String getSpecialLocaleId() {
return SPECIAL_LOCALE_ID;
}
/**
* Adds local search engines for special locale.
*/
public void addSpecialSearchEngines() {
if (!isSpecialLocaleEnabled()) return;
getSpecialLocaleHandler().loadTemplateUrls();
}
/**
* Removes local search engines for special locale.
*/
public void removeSpecialSearchEngines() {
if (isSpecialLocaleEnabled()) return;
getSpecialLocaleHandler().removeTemplateUrls();
}
/**
* Overrides the default search engine to a different search engine we designate. This is a
* no-op if the user has manually changed DSP settings.
*/
public void overrideDefaultSearchEngine() {
if (!isSearchEngineAutoSwitchEnabled() || !isSpecialLocaleEnabled()) return;
getSpecialLocaleHandler().overrideDefaultSearchProvider();
showSnackbar(ContextUtils.getApplicationContext().getString(R.string.using_sogou));
}
/**
* Reverts the temporary change made in {@link #overrideDefaultSearchEngine()}. This is a no-op
* if the user has manually changed DSP settings.
*/
public void revertDefaultSearchEngineOverride() {
if (!isSearchEngineAutoSwitchEnabled() || isSpecialLocaleEnabled()) return;
getSpecialLocaleHandler().setGoogleAsDefaultSearch();
showSnackbar(ContextUtils.getApplicationContext().getString(R.string.using_google));
}
/**
* Switches the default search engine based on the current locale, if the user has delegated
* Chrome to do so. This method also adds some special engines to user's search engine list, as
* long as the user is in this locale.
*/
protected void maybeAutoSwitchSearchEngine() {
SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
boolean wasInSpecialLocale = preferences.getBoolean(PREF_WAS_IN_SPECIAL_LOCALE, false);
boolean isInSpecialLocale = isSpecialLocaleEnabled();
if (wasInSpecialLocale && !isInSpecialLocale) {
revertDefaultSearchEngineOverride();
removeSpecialSearchEngines();
} else if (isInSpecialLocale && !wasInSpecialLocale) {
addSpecialSearchEngines();
overrideDefaultSearchEngine();
} else if (isInSpecialLocale) {
// As long as the user is in the special locale, special engines should be in the list.
addSpecialSearchEngines();
}
preferences.edit().putBoolean(PREF_WAS_IN_SPECIAL_LOCALE, isInSpecialLocale).apply();
}
/**
* Shows a promotion dialog saying the default search engine will be set to Sogou. No-op if
* device is not in special locale.
*
* @return Whether such dialog is needed.
*/
public boolean showSearchEnginePromoIfNeeded(Context context) {
if (!isSpecialLocaleEnabled()) return false;
SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
if (preferences.getBoolean(PREF_PROMO_SHOWN, false)) {
return false;
}
new SearchEnginePromoDialog(context, this).show();
return true;
}
/**
* @return Whether auto switch for search engine is enabled.
*/
public boolean isSearchEngineAutoSwitchEnabled() {
return ContextUtils.getAppSharedPreferences().getBoolean(PREF_AUTO_SWITCH, false);
}
/**
* Sets whether auto switch for search engine is enabled.
*/
public void setSearchEngineAutoSwitch(boolean isEnabled) {
ContextUtils.getAppSharedPreferences().edit().putBoolean(PREF_AUTO_SWITCH, isEnabled)
.apply();
}
/**
* Sets the {@link SnackbarManager} used by this instance.
*/
public void setSnackbarManager(SnackbarManager manager) {
mSnackbarManager = new WeakReference<SnackbarManager>(manager);
}
private void showSnackbar(CharSequence title) {
SnackbarManager manager = mSnackbarManager.get();
if (manager == null) return;
Context context = ContextUtils.getApplicationContext();
Snackbar snackbar = Snackbar.make(title, mSnackbarController, Snackbar.TYPE_NOTIFICATION,
Snackbar.UMA_SPECIAL_LOCALE);
snackbar.setDuration(SNACKBAR_DURATION_MS);
snackbar.setAction(context.getString(R.string.preferences), null);
manager.showSnackbar(snackbar);
}
/**
* Does some extra checking about whether the user is in special locale.
* @param inSpecialLocale Whether the variation service thinks the client is in special locale.
* @return The result after extra confirmation.
*/
protected boolean isReallyInSpecialLocale(boolean inSpecialLocale) {
return inSpecialLocale;
}
private SpecialLocaleHandler getSpecialLocaleHandler() {
if (mLocaleHandler == null) mLocaleHandler = new SpecialLocaleHandler(getSpecialLocaleId());
return mLocaleHandler;
}
}