| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.browser; |
| |
| import com.android.browser.homepages.HomeProvider; |
| import com.android.browser.provider.BrowserProvider; |
| import com.android.browser.search.SearchEngine; |
| import com.android.browser.search.SearchEngines; |
| |
| import android.app.ActivityManager; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.SharedPreferences; |
| import android.content.SharedPreferences.OnSharedPreferenceChangeListener; |
| import android.os.Build; |
| import android.os.Message; |
| import android.preference.PreferenceManager; |
| import android.provider.Browser; |
| import android.webkit.CookieManager; |
| import android.webkit.GeolocationPermissions; |
| import android.webkit.WebIconDatabase; |
| import android.webkit.WebSettings; |
| import android.webkit.WebSettings.AutoFillProfile; |
| import android.webkit.WebSettings.LayoutAlgorithm; |
| import android.webkit.WebSettings.PluginState; |
| import android.webkit.WebSettings.TextSize; |
| import android.webkit.WebSettings.ZoomDensity; |
| import android.webkit.WebStorage; |
| import android.webkit.WebView; |
| import android.webkit.WebViewDatabase; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.WeakHashMap; |
| |
| /** |
| * Class for managing settings |
| */ |
| public class BrowserSettings implements OnSharedPreferenceChangeListener, |
| PreferenceKeys { |
| |
| // TODO: Do something with this UserAgent stuff |
| private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (X11; " + |
| "Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) " + |
| "Chrome/11.0.696.34 Safari/534.24"; |
| |
| private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " + |
| "CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 " + |
| "(KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7"; |
| |
| private static final String IPAD_USERAGENT = "Mozilla/5.0 (iPad; U; " + |
| "CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 " + |
| "(KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10"; |
| |
| private static final String FROYO_USERAGENT = "Mozilla/5.0 (Linux; U; " + |
| "Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 " + |
| "(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"; |
| |
| private static final String HONEYCOMB_USERAGENT = "Mozilla/5.0 (Linux; U; " + |
| "Android 3.1; en-us; Xoom Build/HMJ25) AppleWebKit/534.13 " + |
| "(KHTML, like Gecko) Version/4.0 Safari/534.13"; |
| |
| private static final String USER_AGENTS[] = { null, |
| DESKTOP_USERAGENT, |
| IPHONE_USERAGENT, |
| IPAD_USERAGENT, |
| FROYO_USERAGENT, |
| HONEYCOMB_USERAGENT, |
| }; |
| |
| private static BrowserSettings sInstance; |
| |
| private Context mContext; |
| private SharedPreferences mPrefs; |
| private LinkedList<WeakReference<WebSettings>> mManagedSettings; |
| private Controller mController; |
| private WebStorageSizeManager mWebStorageSizeManager; |
| private AutofillHandler mAutofillHandler; |
| private WeakHashMap<WebSettings, String> mCustomUserAgents; |
| |
| // Cached settings |
| private SearchEngine mSearchEngine; |
| |
| public static void initialize(final Context context) { |
| sInstance = new BrowserSettings(context); |
| } |
| |
| public static BrowserSettings getInstance() { |
| return sInstance; |
| } |
| |
| private BrowserSettings(Context context) { |
| mContext = context; |
| mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext); |
| if (Build.VERSION.CODENAME.equals("REL")) { |
| // This is a release build, always startup with debug disabled |
| setDebugEnabled(false); |
| } |
| mAutofillHandler = new AutofillHandler(mContext); |
| mManagedSettings = new LinkedList<WeakReference<WebSettings>>(); |
| mCustomUserAgents = new WeakHashMap<WebSettings, String>(); |
| mWebStorageSizeManager = new WebStorageSizeManager(mContext, |
| new WebStorageSizeManager.StatFsDiskInfo(getAppCachePath()), |
| new WebStorageSizeManager.WebKitAppCacheInfo(getAppCachePath())); |
| mPrefs.registerOnSharedPreferenceChangeListener(this); |
| mAutofillHandler.asyncLoadFromDb(); |
| } |
| |
| public void setController(Controller controller) { |
| mController = controller; |
| syncSharedSettings(); |
| |
| if (mController != null && (mSearchEngine instanceof InstantSearchEngine)) { |
| ((InstantSearchEngine) mSearchEngine).setController(mController); |
| } |
| } |
| |
| public void startManagingSettings(WebSettings settings) { |
| synchronized (mManagedSettings) { |
| syncStaticSettings(settings); |
| syncSetting(settings); |
| mManagedSettings.add(new WeakReference<WebSettings>(settings)); |
| } |
| } |
| |
| /** |
| * Syncs all the settings that have a Preference UI |
| */ |
| private void syncSetting(WebSettings settings) { |
| settings.setGeolocationEnabled(enableGeolocation()); |
| settings.setJavaScriptEnabled(enableJavascript()); |
| settings.setLightTouchEnabled(enableLightTouch()); |
| settings.setNavDump(enableNavDump()); |
| settings.setShowVisualIndicator(enableVisualIndicator()); |
| settings.setDefaultTextEncodingName(getDefaultTextEncoding()); |
| settings.setDefaultZoom(getDefaultZoom()); |
| settings.setMinimumFontSize(getMinimumFontSize()); |
| settings.setMinimumLogicalFontSize(getMinimumFontSize()); |
| settings.setForceUserScalable(forceEnableUserScalable()); |
| settings.setPluginState(getPluginState()); |
| settings.setTextSize(getTextSize()); |
| settings.setAutoFillEnabled(isAutofillEnabled()); |
| settings.setLayoutAlgorithm(getLayoutAlgorithm()); |
| settings.setJavaScriptCanOpenWindowsAutomatically(blockPopupWindows()); |
| settings.setLoadsImagesAutomatically(loadImages()); |
| settings.setLoadWithOverviewMode(loadPageInOverviewMode()); |
| settings.setSavePassword(rememberPasswords()); |
| settings.setSaveFormData(saveFormdata()); |
| settings.setUseWideViewPort(isWideViewport()); |
| settings.setAutoFillProfile(getAutoFillProfile()); |
| |
| String ua = mCustomUserAgents.get(settings); |
| if (enableUseragentSwitcher() && ua != null) { |
| settings.setUserAgentString(ua); |
| } else { |
| settings.setUserAgentString(USER_AGENTS[getUserAgent()]); |
| } |
| } |
| |
| /** |
| * Syncs all the settings that have no UI |
| * These cannot change, so we only need to set them once per WebSettings |
| */ |
| private void syncStaticSettings(WebSettings settings) { |
| settings.setDefaultFontSize(16); |
| settings.setDefaultFixedFontSize(13); |
| settings.setPageCacheCapacity(getPageCacheCapacity()); |
| |
| // WebView inside Browser doesn't want initial focus to be set. |
| settings.setNeedInitialFocus(false); |
| // Browser supports multiple windows |
| settings.setSupportMultipleWindows(true); |
| // enable smooth transition for better performance during panning or |
| // zooming |
| settings.setEnableSmoothTransition(true); |
| // disable content url access |
| settings.setAllowContentAccess(false); |
| |
| // HTML5 API flags |
| settings.setAppCacheEnabled(true); |
| settings.setDatabaseEnabled(true); |
| settings.setDomStorageEnabled(true); |
| settings.setWorkersEnabled(true); // This only affects V8. |
| |
| // HTML5 configuration parametersettings. |
| settings.setAppCacheMaxSize(mWebStorageSizeManager.getAppCacheMaxSize()); |
| settings.setAppCachePath(getAppCachePath()); |
| settings.setDatabasePath(mContext.getDir("databases", 0).getPath()); |
| settings.setGeolocationDatabasePath(mContext.getDir("geolocation", 0).getPath()); |
| } |
| |
| private void syncSharedSettings() { |
| CookieManager.getInstance().setAcceptCookie(acceptCookies()); |
| if (mController != null) { |
| mController.setShouldShowErrorConsole(enableJavascriptConsole()); |
| } |
| } |
| |
| private void syncManagedSettings() { |
| syncSharedSettings(); |
| synchronized (mManagedSettings) { |
| Iterator<WeakReference<WebSettings>> iter = mManagedSettings.iterator(); |
| while (iter.hasNext()) { |
| WeakReference<WebSettings> ref = iter.next(); |
| WebSettings settings = ref.get(); |
| if (settings == null) { |
| iter.remove(); |
| continue; |
| } |
| syncSetting(settings); |
| } |
| } |
| } |
| |
| @Override |
| public void onSharedPreferenceChanged( |
| SharedPreferences sharedPreferences, String key) { |
| syncManagedSettings(); |
| if (PREF_SEARCH_ENGINE.equals(key)) { |
| updateSearchEngine(false); |
| } |
| if (PREF_USE_INSTANT_SEARCH.equals(key)) { |
| updateSearchEngine(true); |
| } |
| if (PREF_FULLSCREEN.equals(key)) { |
| if (mController.getUi() != null) { |
| mController.getUi().setFullscreen(useFullscreen()); |
| } |
| } |
| } |
| |
| static String getFactoryResetHomeUrl(Context context) { |
| String url = context.getResources().getString(R.string.homepage_base); |
| if (url.indexOf("{CID}") != -1) { |
| url = url.replace("{CID}", |
| BrowserProvider.getClientId(context.getContentResolver())); |
| } |
| return url; |
| } |
| |
| public LayoutAlgorithm getLayoutAlgorithm() { |
| LayoutAlgorithm layoutAlgorithm = LayoutAlgorithm.NORMAL; |
| if (autofitPages()) { |
| layoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS; |
| } |
| if (isDebugEnabled()) { |
| if (isSmallScreen()) { |
| layoutAlgorithm = LayoutAlgorithm.SINGLE_COLUMN; |
| } else { |
| if (isNormalLayout()) { |
| layoutAlgorithm = LayoutAlgorithm.NORMAL; |
| } else { |
| layoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS; |
| } |
| } |
| } |
| return layoutAlgorithm; |
| } |
| |
| // TODO: Cache |
| public int getPageCacheCapacity() { |
| // the cost of one cached page is ~3M (measured using nytimes.com). For |
| // low end devices, we only cache one page. For high end devices, we try |
| // to cache more pages, currently choose 5. |
| if (ActivityManager.staticGetMemoryClass() > 16) { |
| return 5; |
| } else { |
| return 1; |
| } |
| } |
| |
| public WebStorageSizeManager getWebStorageSizeManager() { |
| return mWebStorageSizeManager; |
| } |
| |
| // TODO: Cache |
| private String getAppCachePath() { |
| return mContext.getDir("appcache", 0).getPath(); |
| } |
| |
| private void updateSearchEngine(boolean force) { |
| String searchEngineName = getSearchEngineName(); |
| if (force || mSearchEngine == null || |
| !mSearchEngine.getName().equals(searchEngineName)) { |
| if (mSearchEngine != null) { |
| if (mSearchEngine.supportsVoiceSearch()) { |
| // One or more tabs could have been in voice search mode. |
| // Clear it, since the new SearchEngine may not support |
| // it, or may handle it differently. |
| for (int i = 0; i < mController.getTabControl().getTabCount(); i++) { |
| mController.getTabControl().getTab(i).revertVoiceSearchMode(); |
| } |
| } |
| mSearchEngine.close(); |
| } |
| mSearchEngine = SearchEngines.get(mContext, searchEngineName); |
| |
| if (mController != null && (mSearchEngine instanceof InstantSearchEngine)) { |
| ((InstantSearchEngine) mSearchEngine).setController(mController); |
| } |
| } |
| } |
| |
| public SearchEngine getSearchEngine() { |
| if (mSearchEngine == null) { |
| updateSearchEngine(false); |
| } |
| return mSearchEngine; |
| } |
| |
| public boolean isDebugEnabled() { |
| return mPrefs.getBoolean(PREF_DEBUG_MENU, false); |
| } |
| |
| public void setDebugEnabled(boolean value) { |
| mPrefs.edit().putBoolean(PREF_DEBUG_MENU, value).apply(); |
| } |
| |
| public void clearCache() { |
| WebIconDatabase.getInstance().removeAllIcons(); |
| if (mController != null) { |
| WebView current = mController.getCurrentWebView(); |
| if (current != null) { |
| current.clearCache(true); |
| } |
| } |
| } |
| |
| public void clearCookies() { |
| CookieManager.getInstance().removeAllCookie(); |
| } |
| |
| public void clearHistory() { |
| ContentResolver resolver = mContext.getContentResolver(); |
| Browser.clearHistory(resolver); |
| Browser.clearSearches(resolver); |
| } |
| |
| public void clearFormData() { |
| WebViewDatabase.getInstance(mContext).clearFormData(); |
| if (mController!= null) { |
| WebView currentTopView = mController.getCurrentTopWebView(); |
| if (currentTopView != null) { |
| currentTopView.clearFormData(); |
| } |
| } |
| } |
| |
| public void clearPasswords() { |
| WebViewDatabase db = WebViewDatabase.getInstance(mContext); |
| db.clearUsernamePassword(); |
| db.clearHttpAuthUsernamePassword(); |
| } |
| |
| public void clearDatabases() { |
| WebStorage.getInstance().deleteAllData(); |
| } |
| |
| public void clearLocationAccess() { |
| GeolocationPermissions.getInstance().clearAll(); |
| } |
| |
| public void resetDefaultPreferences() { |
| mPrefs.edit().clear().apply(); |
| syncManagedSettings(); |
| } |
| |
| public AutoFillProfile getAutoFillProfile() { |
| mAutofillHandler.waitForLoad(); |
| return mAutofillHandler.getAutoFillProfile(); |
| } |
| |
| public void setAutoFillProfile(AutoFillProfile profile, Message msg) { |
| mAutofillHandler.waitForLoad(); |
| mAutofillHandler.setAutoFillProfile(profile, msg); |
| } |
| |
| public void toggleDebugSettings() { |
| setDebugEnabled(!isDebugEnabled()); |
| } |
| |
| public boolean hasDesktopUseragent(WebView view) { |
| return view != null && mCustomUserAgents.get(view.getSettings()) != null; |
| } |
| |
| public void toggleDesktopUseragent(WebView view) { |
| if (view == null) { |
| return; |
| } |
| WebSettings settings = view.getSettings(); |
| if (mCustomUserAgents.get(settings) != null) { |
| mCustomUserAgents.remove(settings); |
| settings.setUserAgentString(USER_AGENTS[getUserAgent()]); |
| } else { |
| mCustomUserAgents.put(settings, DESKTOP_USERAGENT); |
| settings.setUserAgentString(DESKTOP_USERAGENT); |
| } |
| } |
| |
| // ----------------------------- |
| // getter/setters for accessibility_preferences.xml |
| // ----------------------------- |
| |
| // TODO: Cache |
| public TextSize getTextSize() { |
| String textSize = mPrefs.getString(PREF_TEXT_SIZE, "NORMAL"); |
| return TextSize.valueOf(textSize); |
| } |
| |
| public int getMinimumFontSize() { |
| return mPrefs.getInt(PREF_MIN_FONT_SIZE, 1); |
| } |
| |
| public boolean forceEnableUserScalable() { |
| return mPrefs.getBoolean(PREF_FORCE_USERSCALABLE, false); |
| } |
| |
| // ----------------------------- |
| // getter/setters for advanced_preferences.xml |
| // ----------------------------- |
| |
| public String getSearchEngineName() { |
| return mPrefs.getString(PREF_SEARCH_ENGINE, SearchEngine.GOOGLE); |
| } |
| |
| public boolean openInBackground() { |
| return mPrefs.getBoolean(PREF_OPEN_IN_BACKGROUND, false); |
| } |
| |
| public boolean enableJavascript() { |
| return mPrefs.getBoolean(PREF_ENABLE_JAVASCRIPT, true); |
| } |
| |
| // TODO: Cache |
| public PluginState getPluginState() { |
| String state = mPrefs.getString(PREF_PLUGIN_STATE, "ON"); |
| return PluginState.valueOf(state); |
| } |
| |
| // TODO: Cache |
| public ZoomDensity getDefaultZoom() { |
| String zoom = mPrefs.getString(PREF_DEFAULT_ZOOM, "MEDIUM"); |
| return ZoomDensity.valueOf(zoom); |
| } |
| |
| public boolean loadPageInOverviewMode() { |
| return mPrefs.getBoolean(PREF_LOAD_PAGE, true); |
| } |
| |
| public boolean autofitPages() { |
| return mPrefs.getBoolean(PREF_AUTOFIT_PAGES, true); |
| } |
| |
| public boolean blockPopupWindows() { |
| return mPrefs.getBoolean(PREF_BLOCK_POPUP_WINDOWS, true); |
| } |
| |
| public boolean loadImages() { |
| return mPrefs.getBoolean(PREF_LOAD_IMAGES, true); |
| } |
| |
| public String getDefaultTextEncoding() { |
| return mPrefs.getString(PREF_DEFAULT_TEXT_ENCODING, null); |
| } |
| |
| // ----------------------------- |
| // getter/setters for general_preferences.xml |
| // ----------------------------- |
| |
| public String getHomePage() { |
| if (useMostVisitedHomepage()) { |
| return HomeProvider.MOST_VISITED; |
| } |
| return mPrefs.getString(PREF_HOMEPAGE, getFactoryResetHomeUrl(mContext)); |
| } |
| |
| public void setHomePage(String value) { |
| mPrefs.edit().putString(PREF_HOMEPAGE, value).apply(); |
| } |
| |
| public boolean isAutofillEnabled() { |
| return mPrefs.getBoolean(PREF_AUTOFILL_ENABLED, true); |
| } |
| |
| public void setAutofillEnabled(boolean value) { |
| mPrefs.edit().putBoolean(PREF_AUTOFILL_ENABLED, value).apply(); |
| } |
| |
| // ----------------------------- |
| // getter/setters for debug_preferences.xml |
| // ----------------------------- |
| |
| public boolean isHardwareAccelerated() { |
| if (!isDebugEnabled()) { |
| return true; |
| } |
| return mPrefs.getBoolean(PREF_ENABLE_HARDWARE_ACCEL, true); |
| } |
| |
| public int getUserAgent() { |
| if (!isDebugEnabled()) { |
| return 0; |
| } |
| return Integer.parseInt(mPrefs.getString(PREF_USER_AGENT, "0")); |
| } |
| |
| // ----------------------------- |
| // getter/setters for hidden_debug_preferences.xml |
| // ----------------------------- |
| |
| public boolean enableVisualIndicator() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_ENABLE_VISUAL_INDICATOR, false); |
| } |
| |
| public boolean enableJavascriptConsole() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_JAVASCRIPT_CONSOLE, true); |
| } |
| |
| public boolean isSmallScreen() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_SMALL_SCREEN, false); |
| } |
| |
| public boolean isWideViewport() { |
| if (!isDebugEnabled()) { |
| return true; |
| } |
| return mPrefs.getBoolean(PREF_WIDE_VIEWPORT, true); |
| } |
| |
| public boolean isNormalLayout() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_NORMAL_LAYOUT, false); |
| } |
| |
| public boolean isTracing() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_ENABLE_TRACING, false); |
| } |
| |
| public boolean enableLightTouch() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_ENABLE_LIGHT_TOUCH, false); |
| } |
| |
| public boolean enableNavDump() { |
| if (!isDebugEnabled()) { |
| return false; |
| } |
| return mPrefs.getBoolean(PREF_ENABLE_NAV_DUMP, false); |
| } |
| |
| public String getJsEngineFlags() { |
| if (!isDebugEnabled()) { |
| return ""; |
| } |
| return mPrefs.getString(PREF_JS_ENGINE_FLAGS, ""); |
| } |
| |
| // ----------------------------- |
| // getter/setters for lab_preferences.xml |
| // ----------------------------- |
| |
| public boolean useQuickControls() { |
| return mPrefs.getBoolean(PREF_ENABLE_QUICK_CONTROLS, false); |
| } |
| |
| public boolean useMostVisitedHomepage() { |
| return mPrefs.getBoolean(PREF_USE_MOST_VISITED_HOMEPAGE, false); |
| } |
| |
| public boolean useInstantSearch() { |
| return mPrefs.getBoolean(PREF_USE_INSTANT_SEARCH, false); |
| } |
| |
| public boolean useFullscreen() { |
| return mPrefs.getBoolean(PREF_FULLSCREEN, false); |
| } |
| |
| public boolean enableUseragentSwitcher() { |
| return mPrefs.getBoolean(PREF_ENABLE_USERAGENT_SWITCHER, false); |
| } |
| |
| // ----------------------------- |
| // getter/setters for privacy_security_preferences.xml |
| // ----------------------------- |
| |
| public boolean showSecurityWarnings() { |
| return mPrefs.getBoolean(PREF_SHOW_SECURITY_WARNINGS, true); |
| } |
| |
| public boolean acceptCookies() { |
| return mPrefs.getBoolean(PREF_ACCEPT_COOKIES, true); |
| } |
| |
| public boolean saveFormdata() { |
| return mPrefs.getBoolean(PREF_SAVE_FORMDATA, true); |
| } |
| |
| public boolean enableGeolocation() { |
| return mPrefs.getBoolean(PREF_ENABLE_GEOLOCATION, true); |
| } |
| |
| public boolean rememberPasswords() { |
| return mPrefs.getBoolean(PREF_REMEMBER_PASSWORDS, true); |
| } |
| |
| } |