Java tutorial
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.linkbubble; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.preference.PreferenceManager; import android.util.Log; import android.view.View; import com.linkbubble.ui.TabView; import com.linkbubble.util.Analytics; import com.linkbubble.util.CrashTracking; import com.linkbubble.util.Util; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeMap; import java.util.Vector; public class Settings { public static final String PREFERENCE_ENABLED = "preference_enabled"; public static final String PREFERENCE_CHECK_FOR_YOUTUBE_EMBEDS = "preference_scan_for_youtube_embeds"; public static final String PREFERENCE_IGNORE_LINKS_FROM = "preference_ignore_links_from"; public static final String PREFERENCE_AUTO_CONTENT_DISPLAY_LINK_LOADED = "preference_auto_content_display_link_loaded"; public static final boolean PREFERENCE_AUTO_CONTENT_DISPLAY_LINK_LOADED_DEFAULT = false; public static final String PREFERENCE_SHOW_UNDO_CLOSE_TAB = "preference_show_undo_close_tab_prompt"; public static final String PREFERENCE_LEFT_CONSUME_BUBBLE = "preference_left_consume_bubble"; public static final String PREFERENCE_LEFT_CONSUME_BUBBLE_PACKAGE_NAME = "preference_left_consume_bubble_package_name"; public static final String PREFERENCE_LEFT_CONSUME_BUBBLE_ACTIVITY_CLASS_NAME = "preference_left_consume_bubble_activity_class_name"; public static final String PREFERENCE_LEFT_CONSUME_BUBBLE_LABEL = "preference_left_consume_bubble_label"; public static final String PREFERENCE_LEFT_CONSUME_BUBBLE_TYPE = "preference_left_consume_bubble_type"; public static final String PREFERENCE_RIGHT_CONSUME_BUBBLE = "preference_right_consume_bubble"; public static final String PREFERENCE_RIGHT_CONSUME_BUBBLE_PACKAGE_NAME = "preference_right_consume_bubble_package_name"; public static final String PREFERENCE_RIGHT_CONSUME_BUBBLE_ACTIVITY_CLASS_NAME = "preference_right_consume_bubble_activity_class_name"; public static final String PREFERENCE_RIGHT_CONSUME_BUBBLE_LABEL = "preference_right_consume_bubble_label"; public static final String PREFERENCE_RIGHT_CONSUME_BUBBLE_TYPE = "preference_right_consume_bubble_type"; //public static final String PREFERENCE_LINK_DOUBLE_TAP = "preference_double_tap"; //public static final String PREFERENCE_LINK_DOUBLE_TAP_PACKAGE_NAME = "preference_double_tap_package_name"; //public static final String PREFERENCE_LINK_DOUBLE_TAP_ACTIVITY_CLASS_NAME = "preference_double_tap_activity_class_name"; //public static final String PREFERENCE_LINK_DOUBLE_TAP_LABEL = "preference_double_tap_bubble_label"; //public static final String PREFERENCE_LINK_DOUBLE_TAP_TYPE = "preference_double_tap_bubble_type"; public static final String PREFERENCE_DEFAULT_BROWSER = "preference_default_browser"; public static final String PREFERENCE_DEFAULT_BROWSER_PACKAGE_NAME = "preference_default_browser_package_name"; public static final String PREFERENCE_DEFAULT_BROWSER_LABEL = "preference_default_browser_bubble_label"; public static final String KEY_ARTICLE_MODE_PREFERENCE = "preference_article_mode"; public static final String KEY_ARTICLE_MODE_ON_WEAR_PREFERENCE = "preference_reading_mode_on_wear"; public static final String PREFERENCE_THEME_DARK = "preference_theme_dark"; public static final String PREFERENCE_COLORED_PROGRESS_INDICATOR = "preference_colored_progress_indicator"; public static final String PREFERENCE_CURRENT_TABS = "preference_current_bubbles"; public static final String PREFERENCE_DEFAULT_APPS = "preference_default_apps"; public static final String PREFERENCE_FALLBACK_REDIRECT_HOSTS = "preference_redirect_hosts"; public static final String PREFERENCE_THEME_TOOLBAR = "preference_theme_toolbar"; public static final String PREFERENCE_AUTO_ARTICLE_MODE = "preference_auto_article_mode"; public static final String PREFERENCE_INCOGNITO_MODE = "preference_incognito"; public static final String PREFERENCE_HIDE_BUBBLES = "preference_hide_bubbles"; public static final String PREFERENCE_WEBVIEW_BATTERY_SAVING_MODE = "preference_webview_battery_save_v2"; public static final String PREFERENCE_TRACKINGPROTECTION_MODE = "preference_trackingprotection"; public static final String PREFERENCE_ADBLOCK_MODE = "preference_adblock"; public static final String PREFERENCE_BLOCK_3P_COOKIES = "preference_block_3p"; public static final String PREFERENCE_HTTPS_EVERYWHERE_MODE = "preference_httpseverywhere"; public static final String PREFERENCE_WEBVIEW_TEXT_ZOOM = "preference_webview_text_zoom2"; public static final int PREFERENCE_WEBVIEW_TEXT_ZOOM_MIN = 50; public static final int PREFERENCE_WEBVIEW_TEXT_ZOOM_DEFAULT = 100; public static final int PREFERENCE_WEBVIEW_TEXT_ZOOM_MAX = 250; public static final String PREFERENCE_USER_AGENT = "preference_user_agent"; private static final String SAY_THANKS_CLICKED = "say_thanks_clicked"; private static final String DEFAULT_APPS_MAP_KEY_HOST = "host"; private static final String DEFAULT_APPS_MAP_KEY_COMPONENT = "component"; private static final String BUBBLE_RESTING_X = "bubble_resting_x"; private static final String BUBBLE_RESTING_Y = "bubble_resting_y"; private static final String WELCOME_MESSAGE_DISPLAYED = "welcome_message_displayed"; private static final String TERMS_ACCEPTED = "terms_accepted"; private static final String LAST_FLUSH_WEBVIEW_CACHE_TIME = "last_flush_cache_time"; private static final String PREFERENCE_DID_RESET_FALLBACK_BROWSER = "did_reset_fallback_browser"; private static final String PREFERENCE_SHOW_NEW_BRAVE_BROWSER = "show_new_brave_browser"; public enum WebViewBatterySaveMode { Aggressive, Default, Off, } enum ColorTheme { Light, Dark, Palette, } /* * */ public static void initModule(Context context) { mInstance = new Settings(context); } /* * */ public static void deinitModule() { mInstance = null; } /* * */ public static Settings get() { return mInstance; } private static Settings mInstance = null; public static class OnConsumeBubblesChangedEvent { } private SharedPreferences mSharedPreferences; private Context mContext; private TreeMap<String, String> mDefaultAppsMap = new TreeMap<String, String>(); private List<Intent> mBrowsers; private List<String> mBrowserPackageNames; private ResolveInfo mYouTubeViewResolveInfo; public ResolveInfo mLinkBubbleEntryActivityResolveInfo; private boolean mCheckedForYouTubeResolveInfo = false; private List<String> mIgnoreLinksFromPackageNames; private WebViewBatterySaveMode mWebViewBatterySaveMode; // The point to save private Point mBubbleRestingPoint = new Point(); // The point used as the return value. Required so we don't overwrite the desired point in landscape mode private Point mTempBubbleRestingPoint = new Point(); private HashSet<String> mFallbackRedirectHosts = new HashSet<>(); static public int COLOR_TEXT_DARK; static public int COLOR_TEXT_LIGHT; static public int COLOR_LINK_DARK; static public int COLOR_LINK_LIGHT; static public int COLOR_CONTENT_VIEW_DARK; static public int COLOR_CONTENT_VIEW_LIGHT; static public int COLOR_PROGRESS_DARK; static public int COLOR_PROGRESS_LIGHT; static public int COLOR_WHITE; static public int COLOR_BLACK; Settings(Context context) { mContext = context; mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); //mDownloadHandlerComponentName = new ComponentName(mContext, DownloadHandlerActivity.class); COLOR_WHITE = mContext.getResources().getColor(android.R.color.white); COLOR_BLACK = mContext.getResources().getColor(android.R.color.black); COLOR_TEXT_DARK = mContext.getResources().getColor(R.color.color_text_dark); COLOR_TEXT_LIGHT = mContext.getResources().getColor(R.color.color_text_light); COLOR_LINK_DARK = mContext.getResources().getColor(R.color.color_link_dark); COLOR_LINK_LIGHT = mContext.getResources().getColor(R.color.color_link_light); COLOR_CONTENT_VIEW_DARK = mContext.getResources().getColor(R.color.color_content_view_dark); COLOR_CONTENT_VIEW_LIGHT = mContext.getResources().getColor(R.color.color_content_view_light); COLOR_PROGRESS_DARK = mContext.getResources().getColor(R.color.color_progress_default_dark); COLOR_PROGRESS_LIGHT = mContext.getResources().getColor(R.color.color_progress_default_light); checkForVersionUpgrade(); setDefaultRightConsumeBubble(); setDefaultLeftConsumeBubble(); if (mSharedPreferences.getBoolean("first_run", true)) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean("first_run", false); editor.putLong(LAST_FLUSH_WEBVIEW_CACHE_TIME, System.currentTimeMillis()); editor.commit(); PackageManager packageManager = mContext.getPackageManager(); configureDefaultApp(packageManager, "https://www.youtube.com/watch?v=_Aj-PRdU7xA", "com.google.android.youtube"); configureDefaultApp(packageManager, "https://plus.google.com/+LinkBubble/posts/RdMoBbbjPUi", "com.google.android.apps.plus"); configureDefaultApp(packageManager, "https://play.google.com/store/apps/details?id=com.linkbubble.playstore&hl=en", "com.android.vending"); configureDefaultApp(packageManager, "https://maps.google.com/maps/ms?msid=212078515518849153944.000434d59f7fc56a57668", "com.google.android.apps.maps"); saveDefaultApps(); } else { // This option is being added in 1.3. For people upgrading from older versions, set the value to force a clear very soon if (mSharedPreferences.getLong(LAST_FLUSH_WEBVIEW_CACHE_TIME, -1) == -1) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putLong(LAST_FLUSH_WEBVIEW_CACHE_TIME, System.currentTimeMillis() - Constant.EMPTY_WEBVIEW_CACHE_INTERVAL); editor.apply(); } // This option is being added in 1.9.58 to reset fallback browser, to set it to tabbed Brave. if (!mSharedPreferences.getBoolean(PREFERENCE_DID_RESET_FALLBACK_BROWSER, false)) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(PREFERENCE_DID_RESET_FALLBACK_BROWSER, true); editor.remove(PREFERENCE_DEFAULT_BROWSER_PACKAGE_NAME); editor.remove(PREFERENCE_DEFAULT_BROWSER_LABEL); editor.apply(); } } configureDefaultApps(mSharedPreferences.getString(PREFERENCE_DEFAULT_APPS, null)); mBubbleRestingPoint.set(-1, -1); loadLinkLoadStats(); loadRecentAppRedirects(); loadIgnoreLinksFromPackageNames(); setWebViewBatterySaveMode( mSharedPreferences.getString(PREFERENCE_WEBVIEW_BATTERY_SAVING_MODE, "aggressive")); HashSet<String> defaultRedirects = new HashSet<>(); defaultRedirects.add("accounts.google.com"); configureFallbackRedirectHosts( mSharedPreferences.getStringSet(PREFERENCE_FALLBACK_REDIRECT_HOSTS, defaultRedirects)); } public boolean showNewBraveBrowserNotification() { // This option is being added in 1.9.58 to show notification about new tabbed Brave browser. if (mSharedPreferences.getBoolean(PREFERENCE_SHOW_NEW_BRAVE_BROWSER, true)) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(PREFERENCE_SHOW_NEW_BRAVE_BROWSER, false); editor.apply(); return true; } return false; } private void checkForVersionUpgrade() { final String key = "lastUpgradeVersion"; int lastUpgradeVersion = mSharedPreferences.getInt(key, -1); int upgradeVersionToSet = -1; if (lastUpgradeVersion < 1) { // Remove all defaults to TapPath String defaultAppsAsString = mSharedPreferences.getString(PREFERENCE_DEFAULT_APPS, null); try { if (defaultAppsAsString != null) { JSONArray defaultApps = new JSONArray(defaultAppsAsString); mDefaultAppsMap.clear(); boolean tapPathFound = false; for (int i = 0; i < defaultApps.length(); i++) { try { JSONObject object = defaultApps.getJSONObject(i); String host = object.getString(DEFAULT_APPS_MAP_KEY_HOST); String flattenedName = object.getString(DEFAULT_APPS_MAP_KEY_COMPONENT); if (flattenedName.contains(BuildConfig.TAP_PATH_PACKAGE_NAME) == false) { mDefaultAppsMap.put(host, flattenedName); } else { tapPathFound = true; //Log.d("blerg", "ignore " + host + ", " + flattenedName); } } catch (JSONException e) { e.printStackTrace(); } } if (tapPathFound) { saveDefaultApps(); } } } catch (JSONException e) { mDefaultAppsMap.clear(); } upgradeVersionToSet = 1; } if (upgradeVersionToSet > -1) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putInt(key, upgradeVersionToSet); editor.apply(); } } private void configureDefaultApp(PackageManager packageManager, String urlAsString, String desiredPackageName) { try { URL url = new URL(urlAsString); List<ResolveInfo> tempResolveInfos = new ArrayList<>(); if (!urlAsString.equals(mContext.getString(R.string.empty_bubble_page))) { tempResolveInfos = getAppsThatHandleUrl(urlAsString, packageManager); } final List<ResolveInfo> resolveInfos = tempResolveInfos; if (null == resolveInfos) { return; } for (ResolveInfo resolveInfo : resolveInfos) { if (resolveInfo.activityInfo != null) { String packageName = resolveInfo.activityInfo.packageName; if (packageName.equals(BuildConfig.APPLICATION_ID) == false && packageName.contains(desiredPackageName)) { setDefaultApp(url.toString(), resolveInfo, false); return; } } } } catch (MalformedURLException ex) { } } public void saveData() { saveLinkLoadStats(); saveRecentAppRedirects(); } public void onOrientationChange() { int bubbleRestingX = mBubbleRestingPoint.x; if (bubbleRestingX == -1) { bubbleRestingX = mSharedPreferences.getInt(BUBBLE_RESTING_X, -1); if (bubbleRestingX == -1) { bubbleRestingX = Config.mBubbleSnapLeftX; } } if (bubbleRestingX < Config.mScreenCenterX) { bubbleRestingX = Config.mBubbleSnapLeftX; } else { bubbleRestingX = Config.mBubbleSnapRightX; } int bubbleRestingY = mBubbleRestingPoint.y; if (bubbleRestingY == -1) { bubbleRestingY = mSharedPreferences.getInt(BUBBLE_RESTING_Y, -1); if (bubbleRestingY == -1) { bubbleRestingY = (int) (Config.mScreenHeight * 0.35f); } } mBubbleRestingPoint.set(bubbleRestingX, bubbleRestingY); } public void updateBrowsers() { if (mBrowsers == null) { mBrowsers = new Vector<Intent>(); mBrowserPackageNames = new ArrayList<String>(); } else { mBrowsers.clear(); mBrowserPackageNames.clear(); } PackageManager packageManager = mContext.getPackageManager(); Intent queryIntent = new Intent(); queryIntent.setAction(Intent.ACTION_VIEW); queryIntent.setData(Uri.parse("http://www.fdasfjsadfdsfas.com")); // Something stupid that no non-browser app will handle List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(queryIntent, PackageManager.GET_RESOLVED_FILTER); String fallbackDefaultBrowserPackageName = null; String fallbackDefaultBrowserActivityClassName = null; for (ResolveInfo resolveInfo : resolveInfos) { IntentFilter filter = resolveInfo.filter; if (filter != null && filter.hasAction(Intent.ACTION_VIEW) && filter.hasCategory(Intent.CATEGORY_BROWSABLE)) { // Ignore LinkBubble from this list if (resolveInfo.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID)) { mLinkBubbleEntryActivityResolveInfo = resolveInfo; } else if (Util.isValidBrowserPackageName(resolveInfo.activityInfo.packageName)) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setClassName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); mBrowsers.add(intent); mBrowserPackageNames.add(resolveInfo.activityInfo.packageName); if (resolveInfo.activityInfo.packageName .equals(mContext.getResources().getString(R.string.tab_based_browser_id_name))) { fallbackDefaultBrowserPackageName = resolveInfo.activityInfo.packageName; fallbackDefaultBrowserActivityClassName = resolveInfo.activityInfo.name; } } } } String defaultBrowserPackage = mSharedPreferences.getString(PREFERENCE_DEFAULT_BROWSER_PACKAGE_NAME, null); //String rightConsumeBubblePackageName = mSharedPreferences.getString(PREFERENCE_RIGHT_CONSUME_BUBBLE_PACKAGE_NAME, null); String leftConsumeBubblePackageName = mSharedPreferences .getString(PREFERENCE_LEFT_CONSUME_BUBBLE_PACKAGE_NAME, null); if (fallbackDefaultBrowserPackageName != null) { try { ApplicationInfo applicationInfo = packageManager .getApplicationInfo(fallbackDefaultBrowserPackageName, 0); String defaultBrowserLabel = packageManager.getApplicationLabel(applicationInfo).toString(); if (defaultBrowserPackage == null || !doesPackageExist(packageManager, defaultBrowserPackage)) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(PREFERENCE_DEFAULT_BROWSER_LABEL, defaultBrowserLabel); editor.putString(PREFERENCE_DEFAULT_BROWSER_PACKAGE_NAME, fallbackDefaultBrowserPackageName); editor.commit(); } if (leftConsumeBubblePackageName != null && !doesPackageExist(packageManager, leftConsumeBubblePackageName)) { setConsumeBubble(Constant.BubbleAction.ConsumeLeft, Constant.ActionType.View, defaultBrowserLabel, fallbackDefaultBrowserPackageName, fallbackDefaultBrowserActivityClassName); } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } } } private boolean doesPackageExist(PackageManager pm, String targetPackage) { try { PackageInfo info = pm.getPackageInfo(targetPackage, PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { return false; } return true; } private ResolveInfo findResolveInfoForPackageName(List<ResolveInfo> resolveInfos, String packageName) { for (ResolveInfo resolveInfo : resolveInfos) { if (resolveInfo.activityInfo.packageName.equals(packageName)) { return resolveInfo; } } return null; } public ResolveInfo getYouTubeViewResolveInfo() { if (mCheckedForYouTubeResolveInfo == false) { PackageManager packageManager = mContext.getPackageManager(); Intent queryIntent = new Intent(); queryIntent.setAction(Intent.ACTION_VIEW); queryIntent.setData(Uri.parse("http://www.youtube.com/watch?v=jNQXAC9IVRw")); List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(queryIntent, PackageManager.GET_RESOLVED_FILTER); for (ResolveInfo resolveInfo : resolveInfos) { if (resolveInfo.activityInfo != null && resolveInfo.activityInfo.packageName.contains("com.google.android.youtube")) { mYouTubeViewResolveInfo = resolveInfo; break; } } mCheckedForYouTubeResolveInfo = true; } return mYouTubeViewResolveInfo; } private void setDefaultRightConsumeBubble() { PackageManager packageManager = mContext.getPackageManager(); String rightConsumeBubblePackageName = mSharedPreferences .getString(PREFERENCE_RIGHT_CONSUME_BUBBLE_PACKAGE_NAME, null); if (rightConsumeBubblePackageName == null || (rightConsumeBubblePackageName != null && !rightConsumeBubblePackageName.equals(BuildConfig.APPLICATION_ID) && !doesPackageExist(packageManager, rightConsumeBubblePackageName))) { setConsumeBubble(Constant.BubbleAction.ConsumeRight, Constant.ActionType.Share, mContext.getResources().getString(R.string.share_picker_label), BuildConfig.APPLICATION_ID, Constant.SHARE_PICKER_NAME); } } private void setDefaultLeftConsumeBubble() { String leftConsumeBubblePackageName = mSharedPreferences .getString(PREFERENCE_LEFT_CONSUME_BUBBLE_PACKAGE_NAME, null); if (leftConsumeBubblePackageName == null) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); PackageManager packageManager = mContext.getPackageManager(); List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0); if (setDefaultLeftConsumeBubble( findResolveInfoForPackageName(resolveInfos, Constant.POCKET_PACKAGE_NAME), packageManager) == false) { if (setDefaultLeftConsumeBubble( findResolveInfoForPackageName(resolveInfos, "com.instapaper.android"), packageManager) == false) { if (setDefaultLeftConsumeBubble( findResolveInfoForPackageName(resolveInfos, "com.facebook.katana"), packageManager) == false) { if (setDefaultLeftConsumeBubble( findResolveInfoForPackageName(resolveInfos, "com.twitter.android"), packageManager) == false) { if (setDefaultLeftConsumeBubble( findResolveInfoForPackageName(resolveInfos, "com.google.android.apps.plus"), packageManager) == false) { if (setDefaultLeftConsumeBubble( findResolveInfoForPackageName(resolveInfos, "com.google.android.gm"), packageManager) == false) { // Can't imagine *none* of the above apps will not be installed too often, but if so, fall back to the first item in the list... setDefaultLeftConsumeBubble(resolveInfos.get(0), packageManager); } } } } } } } } private boolean setDefaultLeftConsumeBubble(ResolveInfo resolveInfo, PackageManager packageManager) { if (resolveInfo != null) { setConsumeBubble(Constant.BubbleAction.ConsumeLeft, Constant.ActionType.Share, resolveInfo.loadLabel(packageManager).toString(), resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); return true; } return false; } public List<Intent> getBrowsers() { if (mBrowsers == null) { updateBrowsers(); } return mBrowsers; } public void initiateBrowsersUpdate() { mBrowsers = null; } public List<String> getBrowserPackageNames() { if (mBrowserPackageNames == null) { updateBrowsers(); } return mBrowserPackageNames; } public void setDefaultBrowser(String label, String packageName) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(PREFERENCE_DEFAULT_BROWSER_LABEL, label); editor.putString(PREFERENCE_DEFAULT_BROWSER_PACKAGE_NAME, packageName); editor.commit(); } public String getDefaultBrowserLabel() { return mSharedPreferences.getString(PREFERENCE_DEFAULT_BROWSER_LABEL, null); } String getDefaultBrowserPackageName() { return mSharedPreferences.getString(PREFERENCE_DEFAULT_BROWSER_PACKAGE_NAME, null); } ComponentName getDefaultBrowserComponentName(Context context) { String defaultBrowserPackageName = getDefaultBrowserPackageName(); if (defaultBrowserPackageName != null) { Intent browserIntent = context.getPackageManager().getLaunchIntentForPackage(defaultBrowserPackageName); if (browserIntent != null) { return browserIntent.getComponent(); } } return null; } public Drawable getDefaultBrowserIcon(Context context) { ComponentName componentName = getDefaultBrowserComponentName(context); if (componentName != null) { try { return context.getPackageManager().getActivityIcon(componentName); } catch (PackageManager.NameNotFoundException e) { Log.e("Exception", e.getMessage(), e); } } return null; } public void setConsumeBubble(Constant.BubbleAction action, Constant.ActionType type, String label, String packageName, String activityClassName) { SharedPreferences.Editor editor = mSharedPreferences.edit(); switch (action) { case ConsumeLeft: editor.putString(PREFERENCE_LEFT_CONSUME_BUBBLE_LABEL, label); editor.putString(PREFERENCE_LEFT_CONSUME_BUBBLE_PACKAGE_NAME, packageName); editor.putString(PREFERENCE_LEFT_CONSUME_BUBBLE_ACTIVITY_CLASS_NAME, activityClassName); editor.putString(PREFERENCE_LEFT_CONSUME_BUBBLE_TYPE, type.name()); break; case ConsumeRight: editor.putString(PREFERENCE_RIGHT_CONSUME_BUBBLE_LABEL, label); editor.putString(PREFERENCE_RIGHT_CONSUME_BUBBLE_PACKAGE_NAME, packageName); editor.putString(PREFERENCE_RIGHT_CONSUME_BUBBLE_ACTIVITY_CLASS_NAME, activityClassName); editor.putString(PREFERENCE_RIGHT_CONSUME_BUBBLE_TYPE, type.name()); break; //case LinkDoubleTap: // editor.putString(PREFERENCE_LINK_DOUBLE_TAP_LABEL, label); // editor.putString(PREFERENCE_LINK_DOUBLE_TAP_PACKAGE_NAME, packageName); // editor.putString(PREFERENCE_LINK_DOUBLE_TAP_ACTIVITY_CLASS_NAME, activityClassName); // editor.putString(PREFERENCE_LINK_DOUBLE_TAP_TYPE, type.name()); // break; } editor.commit(); MainApplication.postEvent(mContext, new OnConsumeBubblesChangedEvent()); } public String getConsumeBubbleLabel(Constant.BubbleAction action) { switch (action) { case ConsumeLeft: return mSharedPreferences.getString(PREFERENCE_LEFT_CONSUME_BUBBLE_LABEL, null); case ConsumeRight: return mSharedPreferences.getString(PREFERENCE_RIGHT_CONSUME_BUBBLE_LABEL, null); //case LinkDoubleTap: // return mSharedPreferences.getString(PREFERENCE_LINK_DOUBLE_TAP_LABEL, mContext.getString(R.string.not_set)); } return null; } String getConsumeBubblePackageName(Constant.BubbleAction action) { switch (action) { case ConsumeLeft: return mSharedPreferences.getString(PREFERENCE_LEFT_CONSUME_BUBBLE_PACKAGE_NAME, null); case ConsumeRight: return mSharedPreferences.getString(PREFERENCE_RIGHT_CONSUME_BUBBLE_PACKAGE_NAME, null); //case LinkDoubleTap: // return mSharedPreferences.getString(PREFERENCE_LINK_DOUBLE_TAP_PACKAGE_NAME, null); } return null; } String getConsumeBubbleActivityClassName(Constant.BubbleAction action) { switch (action) { case ConsumeLeft: return mSharedPreferences.getString(PREFERENCE_LEFT_CONSUME_BUBBLE_ACTIVITY_CLASS_NAME, null); case ConsumeRight: return mSharedPreferences.getString(PREFERENCE_RIGHT_CONSUME_BUBBLE_ACTIVITY_CLASS_NAME, null); //case LinkDoubleTap: // return mSharedPreferences.getString(PREFERENCE_LINK_DOUBLE_TAP_ACTIVITY_CLASS_NAME, null); } return null; } Constant.ActionType getConsumeBubbleActionType(Constant.BubbleAction action) { String actionTypeAsString = null; switch (action) { case ConsumeLeft: actionTypeAsString = mSharedPreferences.getString(PREFERENCE_LEFT_CONSUME_BUBBLE_TYPE, null); break; case ConsumeRight: actionTypeAsString = mSharedPreferences.getString(PREFERENCE_RIGHT_CONSUME_BUBBLE_TYPE, null); break; //case LinkDoubleTap: // actionTypeAsString = mSharedPreferences.getString(PREFERENCE_LINK_DOUBLE_TAP_TYPE, null); // break; } if (actionTypeAsString != null) { if (actionTypeAsString.equals(Constant.ActionType.Share.name())) { return Constant.ActionType.Share; } else if (actionTypeAsString.equals(Constant.ActionType.View.name())) { return Constant.ActionType.View; } } return Constant.ActionType.Unknown; } public Drawable getConsumeBubbleIcon(Constant.BubbleAction action) { return getConsumeBubbleIcon(action, true); } public Drawable getConsumeBubbleIcon(Constant.BubbleAction action, boolean whiteShareIcon) { PackageManager packageManager = mContext.getPackageManager(); try { String packageName = getConsumeBubblePackageName(action); String name = getConsumeBubbleActivityClassName(action); if (packageName != null && name != null) { if (name.equals(Constant.SHARE_PICKER_NAME)) { return mContext.getResources().getDrawable( whiteShareIcon ? R.drawable.ic_share_white_24dp : R.drawable.ic_share_grey600_24dp); } ComponentName componentName = new ComponentName(packageName, name); return packageManager.getActivityIcon(componentName); } else if (packageName != null) { // Try rendering the icon if we only have a packageName. ApplicationInfo app = packageManager.getApplicationInfo(packageName, 0); Drawable icon = packageManager.getApplicationIcon(app); return icon; } } catch (OutOfMemoryError ex) { } catch (PackageManager.NameNotFoundException e) { } return mContext.getResources().getDrawable(R.drawable.ic_launcher); } private void loadIgnoreLinksFromPackageNames() { if (mIgnoreLinksFromPackageNames == null) { mIgnoreLinksFromPackageNames = new ArrayList<String>(); } mIgnoreLinksFromPackageNames.clear(); // Ignore this on L. Hopefully Google reverse this decision... if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { String string = mSharedPreferences.getString(PREFERENCE_IGNORE_LINKS_FROM, null); if (string != null) { String[] split = string.split(","); if (split != null && split.length > 0) { for (String s : split) { mIgnoreLinksFromPackageNames.add(s); } } } } } public void setIgnoreLinksFromPackageNames(ArrayList<String> packageNames) { mIgnoreLinksFromPackageNames.clear(); String result = ""; if (packageNames != null && packageNames.size() > 0) { for (String packageName : packageNames) { result += packageName + ","; mIgnoreLinksFromPackageNames.add(packageName); } } SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(PREFERENCE_IGNORE_LINKS_FROM, result); editor.commit(); } public List<String> getIgnoreLinksFromPackageNames() { return mIgnoreLinksFromPackageNames; } public boolean ignoreLinkFromPackageName(String packageName) { for (String ignore : mIgnoreLinksFromPackageNames) { if (ignore.equals(packageName)) { return true; } } return false; } public boolean getAutoContentDisplayLinkLoaded() { return mSharedPreferences.getBoolean(PREFERENCE_AUTO_CONTENT_DISPLAY_LINK_LOADED, PREFERENCE_AUTO_CONTENT_DISPLAY_LINK_LOADED_DEFAULT); } public boolean isIncognitoMode() { return mSharedPreferences.getBoolean(PREFERENCE_INCOGNITO_MODE, false); } public boolean isHideBubbles() { return mSharedPreferences.getBoolean(PREFERENCE_HIDE_BUBBLES, true); } public boolean isTrackingProtectionEnabled() { return mSharedPreferences.getBoolean(PREFERENCE_TRACKINGPROTECTION_MODE, true); } public boolean isAdBlockEnabled() { return mSharedPreferences.getBoolean(PREFERENCE_ADBLOCK_MODE, true); } public boolean isBlock3PCookiesEnabled() { return mSharedPreferences.getBoolean(PREFERENCE_BLOCK_3P_COOKIES, true); } public boolean isHttpsEverywhereEnabled() { return mSharedPreferences.getBoolean(PREFERENCE_HTTPS_EVERYWHERE_MODE, false); } public void setWebViewBatterySaveMode(String mode) { if (mode.equals("aggressive")) { mWebViewBatterySaveMode = WebViewBatterySaveMode.Aggressive; } else if (mode.equals("off")) { mWebViewBatterySaveMode = WebViewBatterySaveMode.Off; } else { mWebViewBatterySaveMode = WebViewBatterySaveMode.Default; } } public void setWebViewBatterySaveMode(WebViewBatterySaveMode mode) { String value; switch (mode) { case Off: value = "off"; break; case Aggressive: value = "aggressive"; break; case Default: default: value = "default"; break; } SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(PREFERENCE_WEBVIEW_BATTERY_SAVING_MODE, value); editor.apply(); setWebViewBatterySaveMode(value); } public WebViewBatterySaveMode getWebViewBatterySaveMode() { return mWebViewBatterySaveMode; } public String getUserAgentString() { String defaultUserAgent = mSharedPreferences.getString(PREFERENCE_USER_AGENT, "default"); if (defaultUserAgent.equals("chrome_phone")) { return Constant.USER_AGENT_CHROME_PHONE; } else if (defaultUserAgent.equals("chrome_tablet")) { return Constant.USER_AGENT_CHROME_TABLET; } else if (defaultUserAgent.equals("chrome_desktop")) { return Constant.USER_AGENT_CHROME_DESKTOP; } return null; } public boolean isEnabled() { //return mSharedPreferences.getBoolean(PREFERENCE_ENABLED, false); return true; } public boolean checkForYouTubeEmbeds() { return mSharedPreferences.getBoolean(PREFERENCE_CHECK_FOR_YOUTUBE_EMBEDS, false); } public boolean getSayThanksClicked() { return mSharedPreferences.getBoolean(SAY_THANKS_CLICKED, false); } public void setSayThanksClicked(boolean value) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(SAY_THANKS_CLICKED, value); editor.commit(); } void configureFallbackRedirectHosts(Set<String> items) { if (items != null && items.size() > 0) { // Make a copy to as documentation explicitly states not to trust the result // of getStringSet() call. http://stackoverflow.com/a/19949833/328679 mFallbackRedirectHosts = new HashSet<>(items); } else { mFallbackRedirectHosts.clear(); } } public void addFallbackRedirectHost(String host) { mFallbackRedirectHosts.add(host); saveFallbackRedirectHosts(); } public void removeFallbackRedirectHost(String host) { mFallbackRedirectHosts.remove(host); saveFallbackRedirectHosts(); } private void saveFallbackRedirectHosts() { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.remove(PREFERENCE_FALLBACK_REDIRECT_HOSTS); // always remove. See http://stackoverflow.com/a/21401062/328679 if (mFallbackRedirectHosts.size() > 0) { editor.putStringSet(PREFERENCE_FALLBACK_REDIRECT_HOSTS, mFallbackRedirectHosts); } editor.apply(); } public Set<String> getFallbackRedirectHosts() { return mFallbackRedirectHosts; } public boolean redirectUrlToBrowser(URL url) { String host = url.getHost(); String hostAlt = host.contains("www.") ? host.replace("www.", "") : "www." + host; return mFallbackRedirectHosts.contains(host) || mFallbackRedirectHosts.contains(hostAlt); /* * Temporarily enable DownloadHandlerActivity to see if it might be used to handle this URL. If so, redirect the * URL to the default browser rather than allowing an app like ES File Explorer be set as a default app for a host. #338 */ /* boolean result = false; packageManager.setComponentEnabledSetting(mDownloadHandlerComponentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); mDownloadQueryIntent.setAction(Intent.ACTION_VIEW); mDownloadQueryIntent.setData(Uri.parse(url)); List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mDownloadQueryIntent, PackageManager.GET_RESOLVED_FILTER); if (resolveInfos != null && resolveInfos.size() > 0) { String className = DownloadHandlerActivity.class.getName(); for (ResolveInfo resolveInfo : resolveInfos) { if (resolveInfo.activityInfo != null && resolveInfo.activityInfo.name.equals(className)) { result = true; break; } } } packageManager.setComponentEnabledSetting(mDownloadHandlerComponentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); return result; */ } public boolean getAutoArticleMode() { //return Constant.ARTICLE_MODE ? false : mSharedPreferences.getBoolean(PREFERENCE_AUTO_ARTICLE_MODE, false); return false; } public int getWebViewTextZoom() { return mSharedPreferences.getInt(PREFERENCE_WEBVIEW_TEXT_ZOOM, PREFERENCE_WEBVIEW_TEXT_ZOOM_DEFAULT); } public void setWebViewTextZoom(int zoom) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putInt(PREFERENCE_WEBVIEW_TEXT_ZOOM, zoom); editor.commit(); } public boolean getShowUndoCloseTab() { return mSharedPreferences.getBoolean(PREFERENCE_SHOW_UNDO_CLOSE_TAB, true); } public List<ResolveInfo> getAppsThatHandleUrl(String urlAsString, PackageManager packageManager) { List<Intent> browsers = getBrowsers(); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse(urlAsString)); List<ResolveInfo> infos = packageManager.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER); ArrayList<ResolveInfo> results = new ArrayList<ResolveInfo>(); for (ResolveInfo info : infos) { IntentFilter filter = info.filter; if (filter != null && filter.hasAction(Intent.ACTION_VIEW)) { // Check if this item is a browser, and if so, ignore it boolean packageOk = true; for (Intent browser : browsers) { if (info.activityInfo.packageName.equals(browser.getComponent().getPackageName())) { packageOk = false; break; } } if (packageOk) { // Ensure TapPath is always ignored if (info.activityInfo.packageName.contains("com.digitalashes.tappath")) { //Log.d("blerg", "ignore " + info.activityInfo.packageName); packageOk = false; } else { // And some special case code for me to ignore alternate builds if (BuildConfig.DEBUG) { if (info.activityInfo.packageName.equals("com.linkbubble.playstore") || info.activityInfo.packageName.equals("com.brave.playstore")) { //Log.d("blerg", "ignore " + info.activityInfo.packageName); packageOk = false; } } else { if (info.activityInfo.packageName.equals("com.linkbubble.playstore.dev") || info.activityInfo.packageName.equals("com.brave.playstore.dev")) { //Log.d("blerg", "ignore " + info.activityInfo.packageName); packageOk = false; } } } } if (packageOk) { results.add(info); Log.d("appHandles", info.loadLabel(packageManager) + " for url:" + urlAsString); } } } if (results.size() > 0) { return results; } return null; } public ResolveInfo getDefaultAppForUrl(URL url, List<ResolveInfo> resolveInfos) { if (resolveInfos == null || resolveInfos.size() == 0) { return null; } String host = url.getHost(); if (host.length() > 1) { String flattenedComponentName = mDefaultAppsMap.get(host); if (flattenedComponentName != null) { ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName); if (componentName != null) { for (ResolveInfo resolveInfo : resolveInfos) { // Handle crash: https://fabric.io/brave6/android/apps/com.linkbubble.playstore/issues/5623e787f5d3a7f76be5b166 if (resolveInfo == null || resolveInfo.activityInfo == null) { CrashTracking.log("Null resolveInfo when getting default for app: " + resolveInfo); continue; } if (resolveInfo.activityInfo.packageName.equals(componentName.getPackageName()) && resolveInfo.activityInfo.name.equals(componentName.getClassName())) { return resolveInfo; } } if (componentName.getPackageName().equals(mContext.getPackageName())) { return mLinkBubbleEntryActivityResolveInfo; } } } } return null; } public void setDefaultApp(String urlAsString, ResolveInfo resolveInfo) { setDefaultApp(urlAsString, resolveInfo, true); } public void setDefaultApp(String urlAsString, ResolveInfo resolveInfo, boolean save) { try { URL url = new URL(urlAsString); String host = url.getHost(); if (host.length() > 1) { ComponentName componentName = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); addDefaultApp(host, componentName, save); } } catch (MalformedURLException e) { e.printStackTrace(); } } private void addDefaultApp(String host, ComponentName componentName, boolean save) { mDefaultAppsMap.put(host, componentName.flattenToString()); if (save) { saveDefaultApps(); } } public void removeDefaultApp(String host) { if (mDefaultAppsMap.containsKey(host)) { mDefaultAppsMap.remove(host); saveDefaultApps(); } } public Vector<String> loadCurrentTabs() { Vector<String> urls = new Vector<String>(); String json = mSharedPreferences.getString(PREFERENCE_CURRENT_TABS, "[]"); try { JSONArray jsonArray = new JSONArray(json); for (int i = 0; i < jsonArray.length(); ++i) { String urlAsString = jsonArray.getString(i); if (urlAsString.equals(Constant.WELCOME_MESSAGE_URL) == false) { urls.add(urlAsString); } } } catch (JSONException e) { e.printStackTrace(); } return urls; } public void saveCurrentTabs(List<View> bubbles) { if (Constant.SAVE_CURRENT_TABS == false) { return; } JSONArray jsonArray = new JSONArray(); if (bubbles != null) { for (View view : bubbles) { URL url = ((TabView) view).getUrl(); if (url.toString().equals(Constant.NEW_TAB_URL) == false) { jsonArray.put(url.toString()); } } } String currentTabsString = mSharedPreferences.getString(PREFERENCE_CURRENT_TABS, ""); String newTabsString = jsonArray.toString(); if (!currentTabsString.equals(newTabsString)) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(PREFERENCE_CURRENT_TABS, newTabsString); editor.commit(); } } private void saveDefaultApps() { JSONArray jsonArray = new JSONArray(); for (String key : mDefaultAppsMap.keySet()) { String component = mDefaultAppsMap.get(key); JSONObject object = new JSONObject(); try { object.put(DEFAULT_APPS_MAP_KEY_HOST, key); object.put(DEFAULT_APPS_MAP_KEY_COMPONENT, component); jsonArray.put(object); } catch (JSONException e) { e.printStackTrace(); } } SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(PREFERENCE_DEFAULT_APPS, jsonArray.toString()); editor.commit(); } private void configureDefaultApps(String defaultAppsAsString) { try { if (defaultAppsAsString != null) { JSONArray defaultApps = new JSONArray(defaultAppsAsString); mDefaultAppsMap.clear(); for (int i = 0; i < defaultApps.length(); i++) { try { JSONObject object = defaultApps.getJSONObject(i); String host = object.getString(DEFAULT_APPS_MAP_KEY_HOST); String flattenedName = object.getString(DEFAULT_APPS_MAP_KEY_COMPONENT); mDefaultAppsMap.put(host, flattenedName); } catch (JSONException e) { e.printStackTrace(); } } } else { mDefaultAppsMap.clear(); } } catch (JSONException e) { mDefaultAppsMap.clear(); } } public TreeMap<String, ComponentName> getDefaultAppsMap() { if (mDefaultAppsMap != null && mDefaultAppsMap.size() > 0) { TreeMap<String, ComponentName> result = new TreeMap<String, ComponentName>(); for (String host : mDefaultAppsMap.keySet()) { result.put(host, ComponentName.unflattenFromString(mDefaultAppsMap.get(host))); } return result; } return null; } public Point getBubbleRestingPoint() { mTempBubbleRestingPoint.x = mBubbleRestingPoint.x; if (mTempBubbleRestingPoint.x > Config.mScreenCenterX) { mTempBubbleRestingPoint.x = Config.mBubbleSnapRightX; } else { mTempBubbleRestingPoint.x = Config.mBubbleSnapLeftX; } mTempBubbleRestingPoint.y = mBubbleRestingPoint.y; int minYPosition = (int) (Config.mScreenHeight * .8f); if (mTempBubbleRestingPoint.y > minYPosition) { mTempBubbleRestingPoint.y = minYPosition; } return mTempBubbleRestingPoint; } public int getBubbleStartingX(Point bubbleRestingPoint) { float fromX; if (bubbleRestingPoint.x > Config.mScreenCenterX) { fromX = Config.mBubbleSnapRightX + Config.mBubbleWidth; } else { fromX = Config.mBubbleSnapLeftX - Config.mBubbleWidth; } return (int) fromX; } public void setBubbleRestingPoint(int x, int y) { mBubbleRestingPoint.set(x, y); } public void saveBubbleRestingPoint() { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putInt(BUBBLE_RESTING_X, mBubbleRestingPoint.x); editor.putInt(BUBBLE_RESTING_Y, mBubbleRestingPoint.y); editor.commit(); } public void setWelcomeMessageDisplayed(boolean displayed) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(WELCOME_MESSAGE_DISPLAYED, displayed); editor.commit(); } public boolean getWelcomeMessageDisplayed() { return mSharedPreferences.getBoolean(WELCOME_MESSAGE_DISPLAYED, false); } public void setTermsAccepted(boolean accepted) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(TERMS_ACCEPTED, accepted); editor.commit(); } public boolean getTermsAccepted() { return mSharedPreferences.getBoolean(TERMS_ACCEPTED, false); } public boolean debugAutoLoadUrl() { return mSharedPreferences.getBoolean("auto_load_url", false); } public boolean getArticleModeEnabled() { return mSharedPreferences.getBoolean(KEY_ARTICLE_MODE_PREFERENCE, true); } public boolean getArticleModeOnWearEnabled() { return mSharedPreferences.getBoolean(KEY_ARTICLE_MODE_ON_WEAR_PREFERENCE, false); } private static final int APP_CHANGE_ANIM_TIME = 250; private static final String TOTAL_TIME_SAVED_KEY = "total_time_saved"; private static final String TOTAL_LINKS_LOADED_KEY = "total_links_loaded"; public static final String LOAD_TIME_TAG = "LoadTime"; public enum LinkLoadType { PageLoad, // The page was loaded. AppRedirectInstant, // Redirect via MainController (before a ContentView instance is created for this link). AppRedirectBrowser, // Redirect via ContentView. ShareToOtherApp, // Adding to Pocket or sending to Twitter. OpenInOtherApp, // Opening in Chrome. } long mTotalTimeSaved; int mTotalLinksLoaded; public static class LinkLoadTimeStatsUpdatedEvent { } private LinkLoadTimeStatsUpdatedEvent mLinkLoadTimeStatsUpdatedEvent = new LinkLoadTimeStatsUpdatedEvent(); public void trackLinkLoadTime(long timeSaved, LinkLoadType linkLoadType, String url) { switch (linkLoadType) { case AppRedirectInstant: // Add some time for the time taken to animate to the new app timeSaved += APP_CHANGE_ANIM_TIME; break; case AppRedirectBrowser: // Add some time for the time taken to load the browser initially timeSaved += APP_CHANGE_ANIM_TIME; // Add some time for the time taken to animate to the new app timeSaved += APP_CHANGE_ANIM_TIME; break; } mTotalTimeSaved += timeSaved; mTotalLinksLoaded++; Log.d(LOAD_TIME_TAG, "trackLinkLoadTime() - timeSaved:" + ((float) timeSaved / 1000.f) + " seconds, " + linkLoadType + ", " + url); MainApplication.postEvent(mContext, mLinkLoadTimeStatsUpdatedEvent); Analytics.trackTimeSaved(timeSaved); } public long getTotalTimeSaved() { return mTotalTimeSaved; } public long getTimeSavedPerLink() { if (mTotalLinksLoaded > 0) { return mTotalTimeSaved / mTotalLinksLoaded; } return -1; } public void saveLinkLoadStats() { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putLong(TOTAL_TIME_SAVED_KEY, mTotalTimeSaved); editor.putInt(TOTAL_LINKS_LOADED_KEY, mTotalLinksLoaded); editor.commit(); } private void loadLinkLoadStats() { mTotalTimeSaved = mSharedPreferences.getLong(TOTAL_TIME_SAVED_KEY, 0); mTotalLinksLoaded = mSharedPreferences.getInt(TOTAL_LINKS_LOADED_KEY, 0); } private static final int RECENT_REDIRECT_TIME_DELTA = (int) (2.5f * 1000); private static final String LAST_APP_REDIRECTS = "last_app_redirects"; private static final String LAST_APP_REDIRECT_KEY_TIME = "time"; private static final String LAST_APP_REDIRECT_KEY_URL = "url"; private static final int MAX_LAST_APP_REDIRECT_COUNT = 3; private static class LastAppRedirect { String mUrl; long mTime; } private List<LastAppRedirect> mLastAppRedirects = new ArrayList<LastAppRedirect>(MAX_LAST_APP_REDIRECT_COUNT); // Did we *just* redirect to this URL? We need to store this to fix #276 public boolean didRecentlyRedirectToApp(String url) { long currentTime = System.currentTimeMillis(); for (LastAppRedirect lastAppRedirect : mLastAppRedirects) { long timeDelta = currentTime - lastAppRedirect.mTime; if (timeDelta < RECENT_REDIRECT_TIME_DELTA && lastAppRedirect.mUrl.equals(url)) { return true; } } return false; } public void addRedirectToApp(String url) { LastAppRedirect record = null; // try and find a current record with this url for (LastAppRedirect i : mLastAppRedirects) { if (i.mUrl.equals(url)) { record = i; break; } } if (record == null && mLastAppRedirects.size() == MAX_LAST_APP_REDIRECT_COUNT) { // Get the oldest record in the list for (LastAppRedirect i : mLastAppRedirects) { if (record == null) { record = i; } else if (i.mTime < record.mTime) { record = i; } } } if (record == null) { record = new LastAppRedirect(); mLastAppRedirects.add(record); } record.mUrl = url; record.mTime = System.currentTimeMillis(); } private void saveRecentAppRedirects() { JSONArray jsonArray = new JSONArray(); for (LastAppRedirect lastAppRedirect : mLastAppRedirects) { JSONObject object = new JSONObject(); try { object.put(LAST_APP_REDIRECT_KEY_URL, lastAppRedirect.mUrl); object.put(LAST_APP_REDIRECT_KEY_TIME, lastAppRedirect.mTime); jsonArray.put(object); } catch (JSONException e) { e.printStackTrace(); } } SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putString(LAST_APP_REDIRECTS, jsonArray.toString()); editor.commit(); } private void loadRecentAppRedirects() { mLastAppRedirects.clear(); String json = mSharedPreferences.getString(LAST_APP_REDIRECTS, "[]"); try { JSONArray jsonArray = new JSONArray(json); for (int i = 0; i < jsonArray.length(); ++i) { try { JSONObject object = jsonArray.getJSONObject(i); LastAppRedirect lastAppRedirect = new LastAppRedirect(); lastAppRedirect.mUrl = object.getString(LAST_APP_REDIRECT_KEY_URL); lastAppRedirect.mTime = object.getLong(LAST_APP_REDIRECT_KEY_TIME); mLastAppRedirects.add(lastAppRedirect); } catch (JSONException e) { e.printStackTrace(); } } } catch (JSONException e) { e.printStackTrace(); } } public boolean canFlushWebViewCache() { long lastEmptyTime = mSharedPreferences.getLong(LAST_FLUSH_WEBVIEW_CACHE_TIME, -1); if (lastEmptyTime > -1) { long delta = System.currentTimeMillis() - lastEmptyTime; if (delta > Constant.EMPTY_WEBVIEW_CACHE_INTERVAL) { return true; } } return false; } public void updateLastFlushWebViewCacheTime() { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putLong(LAST_FLUSH_WEBVIEW_CACHE_TIME, System.currentTimeMillis()); editor.commit(); } public boolean getDarkThemeEnabled() { return mSharedPreferences.getBoolean(PREFERENCE_THEME_DARK, false); } public void setDarkThemeEnabled(boolean value) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(PREFERENCE_THEME_DARK, value); editor.commit(); } public boolean getColoredProgressIndicator() { return mSharedPreferences.getBoolean(PREFERENCE_COLORED_PROGRESS_INDICATOR, true); } public void setColoredProgressIndicator(boolean value) { SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putBoolean(PREFERENCE_COLORED_PROGRESS_INDICATOR, value); editor.commit(); } public int getThemedDefaultProgressColor() { if (getDarkThemeEnabled()) { return COLOR_PROGRESS_DARK; } return COLOR_PROGRESS_LIGHT; } public int getThemedContentViewColor() { if (getDarkThemeEnabled()) { return COLOR_CONTENT_VIEW_DARK; } return COLOR_CONTENT_VIEW_LIGHT; } public int getThemedTextColor() { if (getDarkThemeEnabled()) { return COLOR_TEXT_DARK; } return COLOR_TEXT_LIGHT; } public int getThemedLinkColor() { if (getDarkThemeEnabled()) { return COLOR_LINK_DARK; } return COLOR_LINK_LIGHT; } public boolean getThemeToolbar() { return mSharedPreferences.getBoolean(PREFERENCE_THEME_TOOLBAR, true); } }