Index: src/org/adblockplus/android/ABPEngine.java |
diff --git a/src/org/adblockplus/android/ABPEngine.java b/src/org/adblockplus/android/ABPEngine.java |
index 14d52152b36093130ee073bfdf469097497a16fa..3be672be429e8642a79f86a13871577e1c2b9fd5 100644 |
--- a/src/org/adblockplus/android/ABPEngine.java |
+++ b/src/org/adblockplus/android/ABPEngine.java |
@@ -17,129 +17,265 @@ |
package org.adblockplus.android; |
-import org.adblockplus.android.updater.UpdaterActivity; |
+import java.util.List; |
+ |
+import org.adblockplus.libadblockplus.AppInfo; |
+import org.adblockplus.libadblockplus.EventCallback; |
+import org.adblockplus.libadblockplus.Filter; |
+import org.adblockplus.libadblockplus.FilterChangeCallback; |
+import org.adblockplus.libadblockplus.FilterEngine; |
+import org.adblockplus.libadblockplus.JsEngine; |
+import org.adblockplus.libadblockplus.LogSystem; |
+import org.adblockplus.libadblockplus.Subscription; |
+import org.adblockplus.libadblockplus.UpdaterCallback; |
+import org.adblockplus.libadblockplus.WebRequest; |
-import android.app.Notification; |
-import android.app.NotificationManager; |
-import android.app.PendingIntent; |
import android.content.Context; |
-import android.content.Intent; |
import android.content.pm.PackageInfo; |
import android.content.pm.PackageManager.NameNotFoundException; |
import android.os.Build.VERSION; |
-import android.support.v4.app.NotificationCompat; |
import android.util.Log; |
-public class ABPEngine |
+public final class ABPEngine |
{ |
- private final static String TAG = "ABPEngine"; |
- private static final int NOTIFICATION_ID = R.string.app_name + 1; |
+ private static final String TAG = Utils.getTag(ABPEngine.class); |
+ |
+ private final Context context; |
- private Context context; |
+ /* |
+ * The fields below are volatile because: |
+ * |
+ * I encountered JNI related bugs/crashes caused by JNI backed Java objects. It seemed that under |
+ * certain conditions the objects were optimized away which resulted in crashes when trying to |
+ * release the object, sometimes even on access. |
+ * |
+ * The only solution that really worked was to declare the variables holding the references |
+ * volatile, this seems to prevent the JNI from 'optimizing away' those objects (as a volatile |
+ * variable might be changed at any time from any thread). |
+ */ |
+ private volatile JsEngine jsEngine; |
+ private volatile FilterEngine filterEngine; |
+ private volatile LogSystem logSystem; |
+ private volatile WebRequest webRequest; |
+ private volatile EventCallback updateCallback; |
+ private volatile UpdaterCallback updaterCallback; |
+ private volatile FilterChangeCallback filterChangeCallback; |
- public ABPEngine(Context context, String basePath) |
+ private ABPEngine(final Context context) |
{ |
this.context = context; |
- String version; |
+ } |
+ |
+ public static AppInfo generateAppInfo(final Context context) |
+ { |
+ String version = "0"; |
try |
{ |
final PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); |
version = info.versionName + "." + info.versionCode; |
- } catch (NameNotFoundException e) |
+ } |
+ catch (final NameNotFoundException e) |
{ |
Log.e(TAG, "Failed to get the application version number", e); |
- version = "0"; |
} |
final String sdkVersion = String.valueOf(VERSION.SDK_INT); |
final String locale = context.getResources().getConfiguration().locale.toString(); |
final boolean developmentBuild = !context.getResources().getBoolean(R.bool.def_release); |
- initialize(basePath, version, sdkVersion, locale, developmentBuild); |
- } |
- public void onFilterChanged(String url, String status, long time) |
- { |
- context.sendBroadcast(new Intent(AdblockPlus.BROADCAST_SUBSCRIPTION_STATUS).putExtra("url", url).putExtra("status", status).putExtra("time", time)); |
+ return AppInfo.builder() |
+ .setVersion(version) |
+ .setApplicationVersion(sdkVersion) |
+ .setLocale(locale) |
+ .setDevelopmentBuild(developmentBuild) |
+ .build(); |
} |
- /** |
- * Called when update event occurred. |
- * @param url Update download address |
- */ |
- public void onUpdateEvent(String url, String error) |
+ public static ABPEngine create(final Context context, final AppInfo appInfo, final String basePath) |
{ |
- Notification notification = getNotification(url, error); |
- NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); |
- notificationManager.notify(NOTIFICATION_ID, notification); |
+ final ABPEngine engine = new ABPEngine(context); |
+ |
+ engine.jsEngine = new JsEngine(appInfo); |
+ engine.jsEngine.setDefaultFileSystem(basePath); |
+ |
+ engine.logSystem = new AndroidLogSystem(); |
+ engine.jsEngine.setLogSystem(engine.logSystem); |
+ |
+ engine.webRequest = new AndroidWebRequest(); |
+ engine.jsEngine.setWebRequest(engine.webRequest); |
+ |
+ engine.updateCallback = new AndroidUpdateAvailableCallback(context); |
+ engine.jsEngine.setEventCallback("updateAvailable", engine.updateCallback); |
+ |
+ engine.filterEngine = new FilterEngine(engine.jsEngine); |
+ engine.filterChangeCallback = new AndroidFilterChangeCallback(context); |
+ engine.filterEngine.setFilterChangeCallback(engine.filterChangeCallback); |
+ |
+ engine.updaterCallback = new AndroidUpdaterCallback(context); |
+ |
+ return engine; |
} |
- private native void initialize(String basePath, String version, String sdkVersion, String locale, boolean developmentBuild); |
+ public void dispose() |
+ { |
+ // Safe disposing (just in case) |
+ if (this.filterEngine != null) |
+ { |
+ this.filterEngine.dispose(); |
+ this.filterEngine = null; |
+ } |
- public native void release(); |
+ if (this.jsEngine != null) |
+ { |
+ this.jsEngine.dispose(); |
+ this.jsEngine = null; |
+ } |
- public native boolean isFirstRun(); |
+ if (this.logSystem != null) |
+ { |
+ this.logSystem.dispose(); |
+ this.logSystem = null; |
+ } |
- public native Subscription[] getListedSubscriptions(); |
+ if (this.webRequest != null) |
+ { |
+ this.webRequest.dispose(); |
+ this.webRequest = null; |
+ } |
- public native Subscription[] getRecommendedSubscriptions(); |
+ if (this.updateCallback != null) |
+ { |
+ this.updateCallback.dispose(); |
+ this.updateCallback = null; |
+ } |
- public native void addSubscription(String url); |
+ if (this.updaterCallback != null) |
+ { |
+ this.updaterCallback.dispose(); |
+ this.updaterCallback = null; |
+ } |
- public native void removeSubscription(String url); |
+ if (this.filterChangeCallback != null) |
+ { |
+ this.filterChangeCallback.dispose(); |
+ this.filterChangeCallback = null; |
+ } |
+ } |
- public native void refreshSubscription(String url); |
+ public boolean isFirstRun() |
+ { |
+ return this.filterEngine.isFirstRun(); |
+ } |
- public native void actualizeSubscriptionStatus(String url); |
+ private static org.adblockplus.android.Subscription convertJsSubscription(final Subscription jsSubscription) |
+ { |
+ final org.adblockplus.android.Subscription subscription = new org.adblockplus.android.Subscription(); |
- public native void setAcceptableAdsEnabled(boolean enabled); |
+ subscription.title = jsSubscription.getProperty("title").toString(); |
+ subscription.url = jsSubscription.getProperty("url").toString(); |
- public native String getDocumentationLink(); |
+ return subscription; |
+ } |
- public native boolean matches(String url, String contentType, String[] documentUrls); |
+ private static org.adblockplus.android.Subscription[] convertJsSubscriptions(final List<Subscription> jsSubscriptions) |
+ { |
+ final org.adblockplus.android.Subscription[] subscriptions = new org.adblockplus.android.Subscription[jsSubscriptions.size()]; |
- public native String[] getSelectorsForDomain(String domain); |
+ for (int i = 0; i < subscriptions.length; i++) |
+ { |
+ subscriptions[i] = convertJsSubscription(jsSubscriptions.get(i)); |
+ } |
- public native void checkUpdates(); |
+ return subscriptions; |
+ } |
- private Notification getNotification(String url, String error) |
+ public org.adblockplus.android.Subscription[] getRecommendedSubscriptions() |
{ |
- final PendingIntent emptyIntent = PendingIntent.getActivity(context, 0, new Intent(), 0); |
+ return convertJsSubscriptions(this.filterEngine.fetchAvailableSubscriptions()); |
+ } |
- NotificationCompat.Builder builder = new NotificationCompat.Builder(context); |
- builder.setContentTitle(context.getText(R.string.app_name)); |
- builder.setSmallIcon(R.drawable.ic_stat_warning); |
- builder.setWhen(System.currentTimeMillis()); |
- builder.setAutoCancel(true); |
- builder.setOnlyAlertOnce(true); |
- builder.setContentIntent(emptyIntent); |
+ public org.adblockplus.android.Subscription[] getListedSubscriptions() |
+ { |
+ return convertJsSubscriptions(this.filterEngine.getListedSubscriptions()); |
+ } |
- if (url != null) |
+ public void setSubscription(final String url) |
+ { |
+ Subscription sub = null; |
+ for (final Subscription s : this.filterEngine.getListedSubscriptions()) |
+ { |
+ if (url.equals(s.getProperty("url").toString())) |
+ { |
+ sub = s; |
+ } |
+ s.removeFromList(); |
+ } |
+ if (sub != null) |
{ |
- builder.setSmallIcon(R.drawable.ic_stat_download); |
+ sub.addToList(); |
+ } |
+ } |
+ public void refreshSubscriptions() |
+ { |
+ for (final Subscription s : this.filterEngine.getListedSubscriptions()) |
+ { |
+ s.updateFilters(); |
+ } |
+ } |
- Intent intent = new Intent(context, UpdaterActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
- intent.setAction("download"); |
- intent.putExtra("url", url); |
- PendingIntent updateIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); |
- builder.setContentIntent(updateIntent); |
- builder.setContentText(context.getString(R.string.msg_update_available)); |
+ public void setAcceptableAdsEnabled(final boolean enabled) |
+ { |
+ final String url = this.filterEngine.getPref("subscriptions_exceptionsurl").toString(); |
+ final Subscription sub = this.filterEngine.getSubscription(url); |
+ if (sub != null) |
+ { |
+ if (enabled) |
+ { |
+ sub.addToList(); |
+ } |
+ else |
+ { |
+ sub.removeFromList(); |
+ } |
} |
- else if (error != null) |
+ } |
+ |
+ public String getDocumentationLink() |
+ { |
+ return this.filterEngine.getPref("documentation_link").toString(); |
+ } |
+ |
+ public boolean matches(final String fullUrl, final String contentType, final String[] referrerChainArray) |
+ { |
+ final Filter filter = this.filterEngine.matches(fullUrl, contentType, referrerChainArray); |
+ |
+ if (filter == null) |
{ |
- //TODO Should we show error message to the user? |
- builder.setContentText(context.getString(R.string.msg_update_fail)); |
+ return false; |
} |
- else |
+ |
+ // hack: if there is no referrer, block only if filter is domain-specific |
+ // (to re-enable in-app ads blocking, proposed on 12.11.2012 Monday meeting) |
+ // (documentUrls contains the referrers on Android) |
+ if (referrerChainArray.length == 0 && (filter.getProperty("text").toString()).contains("||")) |
{ |
- builder.setContentText(context.getString(R.string.msg_update_missing)); |
+ return false; |
} |
- Notification notification = builder.getNotification(); |
- return notification; |
+ return filter.getType() != Filter.Type.EXCEPTION; |
+ } |
+ |
+ public void checkForUpdates() |
+ { |
+ this.filterEngine.forceUpdateCheck(this.updaterCallback); |
} |
- static |
+ public void updateSubscriptionStatus(final String url) |
{ |
- System.loadLibrary("adblockplus-jni"); |
+ final Subscription sub = this.filterEngine.getSubscription(url); |
+ if (sub != null) |
+ { |
+ Utils.updateSubscriptionStatus(this.context, sub); |
+ } |
} |
} |