| Index: src/org/adblockplus/android/AdblockPlus.java |
| diff --git a/src/org/adblockplus/android/AdblockPlus.java b/src/org/adblockplus/android/AdblockPlus.java |
| index 549908932f4f440cc247ad0854c62238969f584d..61d9cb7ad056b118f47aeccbfe6104749925f8f7 100755 |
| --- a/src/org/adblockplus/android/AdblockPlus.java |
| +++ b/src/org/adblockplus/android/AdblockPlus.java |
| @@ -1,561 +1,561 @@ |
| -/* |
| - * This file is part of Adblock Plus <http://adblockplus.org/>, |
| - * Copyright (C) 2006-2014 Eyeo GmbH |
| - * |
| - * Adblock Plus is free software: you can redistribute it and/or modify |
| - * it under the terms of the GNU General Public License version 3 as |
| - * published by the Free Software Foundation. |
| - * |
| - * Adblock Plus is distributed in the hope that it will be useful, |
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| - * GNU General Public License for more details. |
| - * |
| - * You should have received a copy of the GNU General Public License |
| - * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| - */ |
| - |
| -package org.adblockplus.android; |
| - |
| -import java.io.BufferedReader; |
| -import java.io.File; |
| -import java.io.FileNotFoundException; |
| -import java.io.IOException; |
| -import java.io.InputStream; |
| -import java.io.InputStreamReader; |
| -import java.util.ArrayList; |
| -import java.util.Calendar; |
| -import java.util.LinkedHashMap; |
| -import java.util.List; |
| -import java.util.Map; |
| -import java.util.TimeZone; |
| -import java.util.regex.Pattern; |
| - |
| -import org.adblockplus.android.updater.AlarmReceiver; |
| - |
| -import android.app.ActivityManager; |
| -import android.app.ActivityManager.RunningServiceInfo; |
| -import android.app.AlarmManager; |
| -import android.app.Application; |
| -import android.app.PendingIntent; |
| -import android.content.Context; |
| -import android.content.Intent; |
| -import android.content.SharedPreferences; |
| -import android.content.SharedPreferences.Editor; |
| -import android.content.pm.PackageInfo; |
| -import android.content.pm.PackageManager; |
| -import android.content.pm.PackageManager.NameNotFoundException; |
| -import android.net.ConnectivityManager; |
| -import android.net.NetworkInfo; |
| -import android.net.Uri; |
| -import android.os.Build; |
| -import android.preference.PreferenceManager; |
| -import android.provider.Settings; |
| -import android.util.Log; |
| - |
| -public class AdblockPlus extends Application |
| -{ |
| - private final static String TAG = "Application"; |
| - |
| - private final static Pattern RE_JS = Pattern.compile(".*\\.js$", Pattern.CASE_INSENSITIVE); |
| - private final static Pattern RE_CSS = Pattern.compile(".*\\.css$", Pattern.CASE_INSENSITIVE); |
| - private final static Pattern RE_IMAGE = Pattern.compile(".*\\.(?:gif|png|jpe?g|bmp|ico)$", Pattern.CASE_INSENSITIVE); |
| - private final static Pattern RE_FONT = Pattern.compile(".*\\.(?:ttf|woff)$", Pattern.CASE_INSENSITIVE); |
| - private final static Pattern RE_HTML = Pattern.compile(".*\\.html?$", Pattern.CASE_INSENSITIVE); |
| - |
| - /** |
| - * Broadcasted when filtering is enabled or disabled. |
| - */ |
| - public static final String BROADCAST_FILTERING_CHANGE = "org.adblockplus.android.filtering.status"; |
| - /** |
| - * Broadcasted when subscription status changes. |
| - */ |
| - public final static String BROADCAST_SUBSCRIPTION_STATUS = "org.adblockplus.android.subscription.status"; |
| - /** |
| - * Broadcasted when filter match check is performed. |
| - */ |
| - public final static String BROADCAST_FILTER_MATCHES = "org.adblockplus.android.filter.matches"; |
| - |
| - /** |
| - * Cached list of recommended subscriptions. |
| - */ |
| - private Subscription[] subscriptions; |
| - |
| - /** |
| - * Indicates whether filtering is enabled or not. |
| - */ |
| - private boolean filteringEnabled = false; |
| - |
| - private ABPEngine abpEngine; |
| - |
| - private static AdblockPlus instance; |
| - |
| - private static class ReferrerMappingCache extends LinkedHashMap<String, String> |
| - { |
| - private static final long serialVersionUID = 1L; |
| - private static final int MAX_SIZE = 5000; |
| - |
| - public ReferrerMappingCache() |
| - { |
| - super(MAX_SIZE + 1, 0.75f, true); |
| - } |
| - |
| - @Override |
| - protected boolean removeEldestEntry(Map.Entry<String, String> eldest) |
| - { |
| - return size() > MAX_SIZE; |
| - } |
| - }; |
| - |
| - private ReferrerMappingCache referrerMapping = new ReferrerMappingCache(); |
| - |
| - /** |
| - * Returns pointer to itself (singleton pattern). |
| - */ |
| - public static AdblockPlus getApplication() |
| - { |
| - return instance; |
| - } |
| - |
| - public int getBuildNumber() |
| - { |
| - int buildNumber = -1; |
| - try |
| - { |
| - PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0); |
| - buildNumber = pi.versionCode; |
| - } |
| - catch (NameNotFoundException e) |
| - { |
| - // ignore - this shouldn't happen |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - return buildNumber; |
| - } |
| - |
| - /** |
| - * Opens Android application settings |
| - */ |
| - public static void showAppDetails(Context context) |
| - { |
| - String packageName = context.getPackageName(); |
| - Intent intent = new Intent(); |
| - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) |
| - { |
| - // above 2.3 |
| - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); |
| - Uri uri = Uri.fromParts("package", packageName, null); |
| - intent.setData(uri); |
| - } |
| - else |
| - { |
| - // below 2.3 |
| - final String appPkgName = (Build.VERSION.SDK_INT == Build.VERSION_CODES.FROYO ? "pkg" : "com.android.settings.ApplicationPkgName"); |
| - intent.setAction(Intent.ACTION_VIEW); |
| - intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails"); |
| - intent.putExtra(appPkgName, packageName); |
| - } |
| - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| - context.startActivity(intent); |
| - } |
| - |
| - /** |
| - * Returns device name in user-friendly format |
| - */ |
| - public static String getDeviceName() |
| - { |
| - String manufacturer = Build.MANUFACTURER; |
| - String model = Build.MODEL; |
| - if (model.startsWith(manufacturer)) |
| - return capitalize(model); |
| - else |
| - return capitalize(manufacturer) + " " + model; |
| - } |
| - |
| - public static void appendRawTextFile(Context context, StringBuilder text, int id) |
| - { |
| - InputStream inputStream = context.getResources().openRawResource(id); |
| - InputStreamReader in = new InputStreamReader(inputStream); |
| - BufferedReader buf = new BufferedReader(in); |
| - String line; |
| - try |
| - { |
| - while ((line = buf.readLine()) != null) |
| - text.append(line); |
| - } |
| - catch (IOException e) |
| - { |
| - e.printStackTrace(); |
| - } |
| - } |
| - |
| - private static String capitalize(String s) |
| - { |
| - if (s == null || s.length() == 0) |
| - return ""; |
| - char first = s.charAt(0); |
| - if (Character.isUpperCase(first)) |
| - return s; |
| - else |
| - return Character.toUpperCase(first) + s.substring(1); |
| - } |
| - |
| - /** |
| - * Checks if device has a WiFi connection available. |
| - */ |
| - public static boolean isWiFiConnected(Context context) |
| - { |
| - ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| - NetworkInfo networkInfo = null; |
| - if (connectivityManager != null) |
| - { |
| - networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); |
| - } |
| - return networkInfo == null ? false : networkInfo.isConnected(); |
| - } |
| - |
| - /** |
| - * Checks if ProxyService is running. |
| - * |
| - * @return true if service is running |
| - */ |
| - public boolean isServiceRunning() |
| - { |
| - ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); |
| - // Actually it returns not only running services, so extra check is required |
| - for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) |
| - { |
| - if (service.service.getClassName().equals(ProxyService.class.getCanonicalName()) && service.pid > 0) |
| - return true; |
| - } |
| - return false; |
| - } |
| - |
| - /** |
| - * Checks if application can write to external storage. |
| - */ |
| - public boolean checkWriteExternalPermission() |
| - { |
| - String permission = "android.permission.WRITE_EXTERNAL_STORAGE"; |
| - int res = checkCallingOrSelfPermission(permission); |
| - return res == PackageManager.PERMISSION_GRANTED; |
| - } |
| - |
| - public boolean isFirstRun() |
| - { |
| - return abpEngine.isFirstRun(); |
| - } |
| - |
| - /** |
| - * Returns list of known subscriptions. |
| - */ |
| - public Subscription[] getRecommendedSubscriptions() |
| - { |
| - if (subscriptions == null) |
| - subscriptions = abpEngine.getRecommendedSubscriptions(); |
| - return subscriptions; |
| - } |
| - |
| - /** |
| - * Returns list of enabled subscriptions. |
| - */ |
| - public Subscription[] getListedSubscriptions() |
| - { |
| - return abpEngine.getListedSubscriptions(); |
| - } |
| - |
| - /** |
| - * Adds provided subscription and removes previous subscriptions if any. |
| - * |
| - * @param url |
| - * URL of subscription to add |
| - */ |
| - public void setSubscription(String url) |
| - { |
| - Subscription[] subscriptions = abpEngine.getListedSubscriptions(); |
| - for (Subscription subscription : subscriptions) |
| - { |
| - abpEngine.removeSubscription(subscription.url); |
| - } |
| - abpEngine.addSubscription(url); |
| - } |
| - |
| - /** |
| - * Forces subscriptions refresh. |
| - */ |
| - public void refreshSubscriptions() |
| - { |
| - Subscription[] subscriptions = abpEngine.getListedSubscriptions(); |
| - for (Subscription subscription : subscriptions) |
| - { |
| - abpEngine.refreshSubscription(subscription.url); |
| - } |
| - } |
| - |
| - /** |
| - * Enforces subscription status update. |
| - * |
| - * @param url Subscription url |
| - */ |
| - public void actualizeSubscriptionStatus(String url) |
| - { |
| - abpEngine.actualizeSubscriptionStatus(url); |
| - } |
| - |
| - |
| - /** |
| - * Enables or disables Acceptable Ads |
| - */ |
| - public void setAcceptableAdsEnabled(boolean enabled) |
| - { |
| - abpEngine.setAcceptableAdsEnabled(enabled); |
| - } |
| - |
| - public String getAcceptableAdsUrl() |
| - { |
| - final String documentationLink = abpEngine.getDocumentationLink(); |
| - final String locale = getResources().getConfiguration().locale.toString().replace("_", "-"); |
| - return documentationLink.replace("%LINK%", "acceptable_ads").replace("%LANG%", locale); |
| - } |
| - |
| - public void setNotifiedAboutAcceptableAds(boolean notified) |
| - { |
| - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); |
| - final Editor editor = preferences.edit(); |
| - editor.putBoolean("notified_about_acceptable_ads", notified); |
| - editor.commit(); |
| - } |
| - |
| - public boolean isNotifiedAboutAcceptableAds() |
| - { |
| - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); |
| - return preferences.getBoolean("notified_about_acceptable_ads", false); |
| - } |
| - |
| - /** |
| - * Returns ElemHide selectors for domain. |
| - * |
| - * @param domain The domain |
| - * @return A list of CSS selectors |
| - */ |
| - public String[] getSelectorsForDomain(final String domain) |
| - { |
| - /* We need to ignore element hiding rules here to work around two bugs: |
| - * 1. CSS is being injected even when there's an exception rule with $elemhide |
| - * 2. The injected CSS causes blank pages in Chrome for Android |
| - * |
| - * Starting with 1.1.2, we ignored element hiding rules after download anyway, to keep the |
| - * memory usage down. Doing this with libadblockplus is trickier, but would be the clean |
| - * solution. */ |
| - return null; |
| -/* |
| - if (!filteringEnabled) |
| - return null; |
| - |
| - return abpEngine.getSelectorsForDomain(domain); |
| -*/ |
| - } |
| - |
| - /** |
| - * Checks if filters match request parameters. |
| - * |
| - * @param url |
| - * Request URL |
| - * @param query |
| - * Request query string |
| - * @param referrer |
| - * Request referrer header |
| - * @param accept |
| - * Request accept header |
| - * @return true if matched filter was found |
| - * @throws Exception |
| - */ |
| - public boolean matches(String url, String query, String referrer, String accept) |
| - { |
| - final String fullUrl = !"".equals(query) ? url + "?" + query : url; |
| - if (referrer != null) |
| - referrerMapping.put(fullUrl, referrer); |
| - |
| - if (!filteringEnabled) |
| - return false; |
| - |
| - String contentType = null; |
| - |
| - if (accept != null) |
| - { |
| - if (accept.contains("text/css")) |
| - contentType = "STYLESHEET"; |
| - else if (accept.contains("image/*")) |
| - contentType = "IMAGE"; |
| - else if (accept.contains("text/html")) |
| - contentType = "SUBDOCUMENT"; |
| - } |
| - |
| - if (contentType == null) |
| - { |
| - if (RE_JS.matcher(url).matches()) |
| - contentType = "SCRIPT"; |
| - else if (RE_CSS.matcher(url).matches()) |
| - contentType = "STYLESHEET"; |
| - else if (RE_IMAGE.matcher(url).matches()) |
| - contentType = "IMAGE"; |
| - else if (RE_FONT.matcher(url).matches()) |
| - contentType = "FONT"; |
| - else if (RE_HTML.matcher(url).matches()) |
| - contentType = "SUBDOCUMENT"; |
| - } |
| - if (contentType == null) |
| - contentType = "OTHER"; |
| - |
| - final List<String> referrerChain = buildReferrerChain(referrer); |
| - Log.d("Referrer chain", fullUrl + ": " + referrerChain.toString()); |
| - String[] referrerChainArray = referrerChain.toArray(new String[referrerChain.size()]); |
| - return abpEngine.matches(fullUrl, contentType, referrerChainArray); |
| - } |
| - |
| - private List<String> buildReferrerChain(String url) |
| - { |
| - final List<String> referrerChain = new ArrayList<String>(); |
| - // We need to limit the chain length to ensure we don't block indefinitely if there's |
| - // a referrer loop. |
| - final int maxChainLength = 10; |
| - for (int i = 0; i < maxChainLength && url != null; i++) |
| - { |
| - referrerChain.add(0, url); |
| - url = referrerMapping.get(url); |
| - } |
| - return referrerChain; |
| - } |
| - |
| - /** |
| - * Checks if filtering is enabled. |
| - */ |
| - public boolean isFilteringEnabled() |
| - { |
| - return filteringEnabled; |
| - } |
| - |
| - /** |
| - * Enables or disables filtering. |
| - */ |
| - public void setFilteringEnabled(boolean enable) |
| - { |
| - filteringEnabled = enable; |
| - sendBroadcast(new Intent(BROADCAST_FILTERING_CHANGE).putExtra("enabled", filteringEnabled)); |
| - } |
| - |
| - /** |
| - * Starts ABP engine. It also initiates subscription refresh if it is enabled |
| - * in user settings. |
| - */ |
| - public void startEngine() |
| - { |
| - if (abpEngine == null) |
| - { |
| - File basePath = getFilesDir(); |
| - abpEngine = new ABPEngine(this, basePath.getAbsolutePath()); |
| - } |
| - } |
| - |
| - /** |
| - * Stops ABP engine. |
| - */ |
| - public void stopEngine() |
| - { |
| - if (abpEngine != null) |
| - { |
| - abpEngine.release(); |
| - abpEngine = null; |
| - Log.i(TAG, "stopEngine"); |
| - } |
| - } |
| - |
| - /** |
| - * Initiates immediate interactive check for available update. |
| - */ |
| - public void checkUpdates() |
| - { |
| - abpEngine.checkUpdates(); |
| - } |
| - |
| - /** |
| - * Sets Alarm to call updater after specified number of minutes or after one |
| - * day if |
| - * minutes are set to 0. |
| - * |
| - * @param minutes |
| - * number of minutes to wait |
| - */ |
| - public void scheduleUpdater(int minutes) |
| - { |
| - Calendar updateTime = Calendar.getInstance(); |
| - |
| - if (minutes == 0) |
| - { |
| - // Start update checks at 10:00 GMT... |
| - updateTime.setTimeZone(TimeZone.getTimeZone("GMT")); |
| - updateTime.set(Calendar.HOUR_OF_DAY, 10); |
| - updateTime.set(Calendar.MINUTE, 0); |
| - // ...next day |
| - updateTime.add(Calendar.HOUR_OF_DAY, 24); |
| - // Spread out the “mass downloading” for 6 hours |
| - updateTime.add(Calendar.MINUTE, (int) (Math.random() * 60 * 6)); |
| - } |
| - else |
| - { |
| - updateTime.add(Calendar.MINUTE, minutes); |
| - } |
| - |
| - Intent updater = new Intent(this, AlarmReceiver.class); |
| - PendingIntent recurringUpdate = PendingIntent.getBroadcast(this, 0, updater, PendingIntent.FLAG_CANCEL_CURRENT); |
| - // Set non-waking alarm |
| - AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE); |
| - alarms.set(AlarmManager.RTC, updateTime.getTimeInMillis(), recurringUpdate); |
| - } |
| - |
| - @Override |
| - public void onCreate() |
| - { |
| - super.onCreate(); |
| - instance = this; |
| - |
| - // Check for crash report |
| - try |
| - { |
| - InputStreamReader reportFile = new InputStreamReader(openFileInput(CrashHandler.REPORT_FILE)); |
| - final char[] buffer = new char[0x1000]; |
| - StringBuilder out = new StringBuilder(); |
| - int read; |
| - do |
| - { |
| - read = reportFile.read(buffer, 0, buffer.length); |
| - if (read > 0) |
| - out.append(buffer, 0, read); |
| - } |
| - while (read >= 0); |
| - String report = out.toString(); |
| - if (!"".equals(report)) |
| - { |
| - final Intent intent = new Intent(this, CrashReportDialog.class); |
| - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| - intent.putExtra("report", report); |
| - startActivity(intent); |
| - } |
| - } |
| - catch (FileNotFoundException e) |
| - { |
| - // ignore |
| - } |
| - catch (IOException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - |
| - // Set crash handler |
| - Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(this)); |
| - |
| - // Initiate update check |
| - scheduleUpdater(0); |
| - } |
| -} |
| +/* |
| + * This file is part of Adblock Plus <http://adblockplus.org/>, |
| + * Copyright (C) 2006-2014 Eyeo GmbH |
| + * |
| + * Adblock Plus is free software: you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 3 as |
| + * published by the Free Software Foundation. |
| + * |
| + * Adblock Plus is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| + |
| +package org.adblockplus.android; |
| + |
| +import java.io.BufferedReader; |
| +import java.io.File; |
| +import java.io.FileNotFoundException; |
| +import java.io.IOException; |
| +import java.io.InputStream; |
| +import java.io.InputStreamReader; |
| +import java.util.ArrayList; |
| +import java.util.Calendar; |
| +import java.util.LinkedHashMap; |
| +import java.util.List; |
| +import java.util.Map; |
| +import java.util.TimeZone; |
| +import java.util.regex.Pattern; |
| + |
| +import org.adblockplus.android.updater.AlarmReceiver; |
| + |
| +import android.app.ActivityManager; |
| +import android.app.ActivityManager.RunningServiceInfo; |
| +import android.app.AlarmManager; |
| +import android.app.Application; |
| +import android.app.PendingIntent; |
| +import android.content.Context; |
| +import android.content.Intent; |
| +import android.content.SharedPreferences; |
| +import android.content.SharedPreferences.Editor; |
| +import android.content.pm.PackageInfo; |
| +import android.content.pm.PackageManager; |
| +import android.content.pm.PackageManager.NameNotFoundException; |
| +import android.net.ConnectivityManager; |
| +import android.net.NetworkInfo; |
| +import android.net.Uri; |
| +import android.os.Build; |
| +import android.preference.PreferenceManager; |
| +import android.provider.Settings; |
| +import android.util.Log; |
| + |
| +public class AdblockPlus extends Application |
| +{ |
| + private final static String TAG = "Application"; |
| + |
| + private final static Pattern RE_JS = Pattern.compile(".*\\.js$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_CSS = Pattern.compile(".*\\.css$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_IMAGE = Pattern.compile(".*\\.(?:gif|png|jpe?g|bmp|ico)$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_FONT = Pattern.compile(".*\\.(?:ttf|woff)$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_HTML = Pattern.compile(".*\\.html?$", Pattern.CASE_INSENSITIVE); |
| + |
| + /** |
| + * Broadcasted when filtering is enabled or disabled. |
| + */ |
| + public static final String BROADCAST_FILTERING_CHANGE = "org.adblockplus.android.filtering.status"; |
| + /** |
| + * Broadcasted when subscription status changes. |
| + */ |
| + public final static String BROADCAST_SUBSCRIPTION_STATUS = "org.adblockplus.android.subscription.status"; |
| + /** |
| + * Broadcasted when filter match check is performed. |
| + */ |
| + public final static String BROADCAST_FILTER_MATCHES = "org.adblockplus.android.filter.matches"; |
| + |
| + /** |
| + * Cached list of recommended subscriptions. |
| + */ |
| + private Subscription[] subscriptions; |
| + |
| + /** |
| + * Indicates whether filtering is enabled or not. |
| + */ |
| + private boolean filteringEnabled = false; |
| + |
| + private ABPEngine abpEngine; |
| + |
| + private static AdblockPlus instance; |
| + |
| + private static class ReferrerMappingCache extends LinkedHashMap<String, String> |
| + { |
| + private static final long serialVersionUID = 1L; |
| + private static final int MAX_SIZE = 5000; |
| + |
| + public ReferrerMappingCache() |
| + { |
| + super(MAX_SIZE + 1, 0.75f, true); |
| + } |
| + |
| + @Override |
| + protected boolean removeEldestEntry(Map.Entry<String, String> eldest) |
| + { |
| + return size() > MAX_SIZE; |
| + } |
| + }; |
| + |
| + private ReferrerMappingCache referrerMapping = new ReferrerMappingCache(); |
| + |
| + /** |
| + * Returns pointer to itself (singleton pattern). |
| + */ |
| + public static AdblockPlus getApplication() |
| + { |
| + return instance; |
| + } |
| + |
| + public int getBuildNumber() |
| + { |
| + int buildNumber = -1; |
| + try |
| + { |
| + PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0); |
| + buildNumber = pi.versionCode; |
| + } |
| + catch (NameNotFoundException e) |
| + { |
| + // ignore - this shouldn't happen |
| + Log.e(TAG, e.getMessage(), e); |
| + } |
| + return buildNumber; |
| + } |
| + |
| + /** |
| + * Opens Android application settings |
| + */ |
| + public static void showAppDetails(Context context) |
| + { |
| + String packageName = context.getPackageName(); |
| + Intent intent = new Intent(); |
| + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) |
| + { |
| + // above 2.3 |
| + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); |
| + Uri uri = Uri.fromParts("package", packageName, null); |
| + intent.setData(uri); |
| + } |
| + else |
| + { |
| + // below 2.3 |
| + final String appPkgName = (Build.VERSION.SDK_INT == Build.VERSION_CODES.FROYO ? "pkg" : "com.android.settings.ApplicationPkgName"); |
| + intent.setAction(Intent.ACTION_VIEW); |
| + intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails"); |
| + intent.putExtra(appPkgName, packageName); |
| + } |
| + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| + context.startActivity(intent); |
| + } |
| + |
| + /** |
| + * Returns device name in user-friendly format |
| + */ |
| + public static String getDeviceName() |
| + { |
| + String manufacturer = Build.MANUFACTURER; |
| + String model = Build.MODEL; |
| + if (model.startsWith(manufacturer)) |
| + return capitalize(model); |
| + else |
| + return capitalize(manufacturer) + " " + model; |
| + } |
| + |
| + public static void appendRawTextFile(Context context, StringBuilder text, int id) |
| + { |
| + InputStream inputStream = context.getResources().openRawResource(id); |
| + InputStreamReader in = new InputStreamReader(inputStream); |
| + BufferedReader buf = new BufferedReader(in); |
| + String line; |
| + try |
| + { |
| + while ((line = buf.readLine()) != null) |
| + text.append(line); |
| + } |
| + catch (IOException e) |
| + { |
| + e.printStackTrace(); |
| + } |
| + } |
| + |
| + private static String capitalize(String s) |
| + { |
| + if (s == null || s.length() == 0) |
| + return ""; |
| + char first = s.charAt(0); |
| + if (Character.isUpperCase(first)) |
| + return s; |
| + else |
| + return Character.toUpperCase(first) + s.substring(1); |
| + } |
| + |
| + /** |
| + * Checks if device has a WiFi connection available. |
| + */ |
| + public static boolean isWiFiConnected(Context context) |
| + { |
| + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| + NetworkInfo networkInfo = null; |
| + if (connectivityManager != null) |
| + { |
| + networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); |
| + } |
| + return networkInfo == null ? false : networkInfo.isConnected(); |
| + } |
| + |
| + /** |
| + * Checks if ProxyService is running. |
| + * |
| + * @return true if service is running |
| + */ |
| + public boolean isServiceRunning() |
| + { |
| + ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); |
| + // Actually it returns not only running services, so extra check is required |
| + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) |
| + { |
| + if (service.service.getClassName().equals(ProxyService.class.getCanonicalName()) && service.pid > 0) |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + /** |
| + * Checks if application can write to external storage. |
| + */ |
| + public boolean checkWriteExternalPermission() |
| + { |
| + String permission = "android.permission.WRITE_EXTERNAL_STORAGE"; |
| + int res = checkCallingOrSelfPermission(permission); |
| + return res == PackageManager.PERMISSION_GRANTED; |
| + } |
| + |
| + public boolean isFirstRun() |
| + { |
| + return abpEngine.isFirstRun(); |
| + } |
| + |
| + /** |
| + * Returns list of known subscriptions. |
| + */ |
| + public Subscription[] getRecommendedSubscriptions() |
| + { |
| + if (subscriptions == null) |
| + subscriptions = abpEngine.getRecommendedSubscriptions(); |
| + return subscriptions; |
| + } |
| + |
| + /** |
| + * Returns list of enabled subscriptions. |
| + */ |
| + public Subscription[] getListedSubscriptions() |
| + { |
| + return abpEngine.getListedSubscriptions(); |
| + } |
| + |
| + /** |
| + * Adds provided subscription and removes previous subscriptions if any. |
| + * |
| + * @param url |
| + * URL of subscription to add |
| + */ |
| + public void setSubscription(String url) |
| + { |
| + Subscription[] subscriptions = abpEngine.getListedSubscriptions(); |
| + for (Subscription subscription : subscriptions) |
| + { |
| + abpEngine.removeSubscription(subscription.url); |
| + } |
| + abpEngine.addSubscription(url); |
| + } |
| + |
| + /** |
| + * Forces subscriptions refresh. |
| + */ |
| + public void refreshSubscriptions() |
| + { |
| + Subscription[] subscriptions = abpEngine.getListedSubscriptions(); |
| + for (Subscription subscription : subscriptions) |
| + { |
| + abpEngine.refreshSubscription(subscription.url); |
| + } |
| + } |
| + |
| + /** |
| + * Enforces subscription status update. |
| + * |
| + * @param url Subscription url |
| + */ |
| + public void actualizeSubscriptionStatus(String url) |
| + { |
| + abpEngine.actualizeSubscriptionStatus(url); |
| + } |
| + |
| + |
| + /** |
| + * Enables or disables Acceptable Ads |
| + */ |
| + public void setAcceptableAdsEnabled(boolean enabled) |
| + { |
| + abpEngine.setAcceptableAdsEnabled(enabled); |
| + } |
| + |
| + public String getAcceptableAdsUrl() |
| + { |
| + final String documentationLink = abpEngine.getDocumentationLink(); |
| + final String locale = getResources().getConfiguration().locale.toString().replace("_", "-"); |
| + return documentationLink.replace("%LINK%", "acceptable_ads").replace("%LANG%", locale); |
| + } |
| + |
| + public void setNotifiedAboutAcceptableAds(boolean notified) |
| + { |
| + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); |
| + final Editor editor = preferences.edit(); |
| + editor.putBoolean("notified_about_acceptable_ads", notified); |
| + editor.commit(); |
| + } |
| + |
| + public boolean isNotifiedAboutAcceptableAds() |
| + { |
| + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); |
| + return preferences.getBoolean("notified_about_acceptable_ads", false); |
| + } |
| + |
| + /** |
| + * Returns ElemHide selectors for domain. |
| + * |
| + * @param domain The domain |
| + * @return A list of CSS selectors |
| + */ |
| + public String[] getSelectorsForDomain(final String domain) |
| + { |
| + /* We need to ignore element hiding rules here to work around two bugs: |
| + * 1. CSS is being injected even when there's an exception rule with $elemhide |
| + * 2. The injected CSS causes blank pages in Chrome for Android |
| + * |
| + * Starting with 1.1.2, we ignored element hiding rules after download anyway, to keep the |
| + * memory usage down. Doing this with libadblockplus is trickier, but would be the clean |
| + * solution. */ |
| + return null; |
| +/* |
| + if (!filteringEnabled) |
| + return null; |
| + |
| + return abpEngine.getSelectorsForDomain(domain); |
| +*/ |
| + } |
| + |
| + /** |
| + * Checks if filters match request parameters. |
| + * |
| + * @param url |
| + * Request URL |
| + * @param query |
| + * Request query string |
| + * @param referrer |
| + * Request referrer header |
| + * @param accept |
| + * Request accept header |
| + * @return true if matched filter was found |
| + * @throws Exception |
| + */ |
| + public boolean matches(String url, String query, String referrer, String accept) |
| + { |
| + final String fullUrl = !"".equals(query) ? url + "?" + query : url; |
| + if (referrer != null) |
| + referrerMapping.put(fullUrl, referrer); |
| + |
| + if (!filteringEnabled) |
| + return false; |
| + |
| + String contentType = null; |
| + |
| + if (accept != null) |
| + { |
| + if (accept.contains("text/css")) |
| + contentType = "STYLESHEET"; |
| + else if (accept.contains("image/*")) |
| + contentType = "IMAGE"; |
| + else if (accept.contains("text/html")) |
| + contentType = "SUBDOCUMENT"; |
| + } |
| + |
| + if (contentType == null) |
| + { |
| + if (RE_JS.matcher(url).matches()) |
| + contentType = "SCRIPT"; |
| + else if (RE_CSS.matcher(url).matches()) |
| + contentType = "STYLESHEET"; |
| + else if (RE_IMAGE.matcher(url).matches()) |
| + contentType = "IMAGE"; |
| + else if (RE_FONT.matcher(url).matches()) |
| + contentType = "FONT"; |
| + else if (RE_HTML.matcher(url).matches()) |
| + contentType = "SUBDOCUMENT"; |
| + } |
| + if (contentType == null) |
| + contentType = "OTHER"; |
| + |
| + final List<String> referrerChain = buildReferrerChain(referrer); |
| + Log.d("Referrer chain", fullUrl + ": " + referrerChain.toString()); |
| + String[] referrerChainArray = referrerChain.toArray(new String[referrerChain.size()]); |
| + return abpEngine.matches(fullUrl, contentType, referrerChainArray); |
| + } |
| + |
| + private List<String> buildReferrerChain(String url) |
| + { |
| + final List<String> referrerChain = new ArrayList<String>(); |
| + // We need to limit the chain length to ensure we don't block indefinitely if there's |
| + // a referrer loop. |
| + final int maxChainLength = 10; |
| + for (int i = 0; i < maxChainLength && url != null; i++) |
| + { |
| + referrerChain.add(0, url); |
| + url = referrerMapping.get(url); |
| + } |
| + return referrerChain; |
| + } |
| + |
| + /** |
| + * Checks if filtering is enabled. |
| + */ |
| + public boolean isFilteringEnabled() |
| + { |
| + return filteringEnabled; |
| + } |
| + |
| + /** |
| + * Enables or disables filtering. |
| + */ |
| + public void setFilteringEnabled(boolean enable) |
| + { |
| + filteringEnabled = enable; |
| + sendBroadcast(new Intent(BROADCAST_FILTERING_CHANGE).putExtra("enabled", filteringEnabled)); |
| + } |
| + |
| + /** |
| + * Starts ABP engine. It also initiates subscription refresh if it is enabled |
| + * in user settings. |
| + */ |
| + public void startEngine() |
| + { |
| + if (abpEngine == null) |
| + { |
| + File basePath = getFilesDir(); |
| + abpEngine = new ABPEngine(this, basePath.getAbsolutePath()); |
| + } |
| + } |
| + |
| + /** |
| + * Stops ABP engine. |
| + */ |
| + public void stopEngine() |
| + { |
| + if (abpEngine != null) |
| + { |
| + abpEngine.release(); |
| + abpEngine = null; |
| + Log.i(TAG, "stopEngine"); |
| + } |
| + } |
| + |
| + /** |
| + * Initiates immediate interactive check for available update. |
| + */ |
| + public void checkUpdates() |
| + { |
| + abpEngine.checkUpdates(); |
| + } |
| + |
| + /** |
| + * Sets Alarm to call updater after specified number of minutes or after one |
| + * day if |
| + * minutes are set to 0. |
| + * |
| + * @param minutes |
| + * number of minutes to wait |
| + */ |
| + public void scheduleUpdater(int minutes) |
| + { |
| + Calendar updateTime = Calendar.getInstance(); |
| + |
| + if (minutes == 0) |
| + { |
| + // Start update checks at 10:00 GMT... |
| + updateTime.setTimeZone(TimeZone.getTimeZone("GMT")); |
| + updateTime.set(Calendar.HOUR_OF_DAY, 10); |
| + updateTime.set(Calendar.MINUTE, 0); |
| + // ...next day |
| + updateTime.add(Calendar.HOUR_OF_DAY, 24); |
| + // Spread out the “mass downloading” for 6 hours |
| + updateTime.add(Calendar.MINUTE, (int) (Math.random() * 60 * 6)); |
| + } |
| + else |
| + { |
| + updateTime.add(Calendar.MINUTE, minutes); |
| + } |
| + |
| + Intent updater = new Intent(this, AlarmReceiver.class); |
| + PendingIntent recurringUpdate = PendingIntent.getBroadcast(this, 0, updater, PendingIntent.FLAG_CANCEL_CURRENT); |
| + // Set non-waking alarm |
| + AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE); |
| + alarms.set(AlarmManager.RTC, updateTime.getTimeInMillis(), recurringUpdate); |
| + } |
| + |
| + @Override |
| + public void onCreate() |
| + { |
| + super.onCreate(); |
| + instance = this; |
| + |
| + // Check for crash report |
| + try |
| + { |
| + InputStreamReader reportFile = new InputStreamReader(openFileInput(CrashHandler.REPORT_FILE)); |
| + final char[] buffer = new char[0x1000]; |
| + StringBuilder out = new StringBuilder(); |
| + int read; |
| + do |
| + { |
| + read = reportFile.read(buffer, 0, buffer.length); |
| + if (read > 0) |
| + out.append(buffer, 0, read); |
| + } |
| + while (read >= 0); |
| + String report = out.toString(); |
| + if (!"".equals(report)) |
| + { |
| + final Intent intent = new Intent(this, CrashReportDialog.class); |
| + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| + intent.putExtra("report", report); |
| + startActivity(intent); |
| + } |
| + } |
| + catch (FileNotFoundException e) |
| + { |
| + // ignore |
| + } |
| + catch (IOException e) |
| + { |
| + // TODO Auto-generated catch block |
| + Log.e(TAG, e.getMessage(), e); |
| + } |
| + |
| + // Set crash handler |
| + Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(this)); |
| + |
| + // Initiate update check |
| + scheduleUpdater(0); |
| + } |
| +} |