| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
| 13 * | 13 * |
| 14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 */ | 16 */ |
| 17 | 17 |
| 18 package org.adblockplus.libadblockplus.android.settings; | 18 package org.adblockplus.libadblockplus.android.settings; |
| 19 | 19 |
| 20 import android.content.Context; | 20 import android.content.Context; |
| 21 import android.content.SharedPreferences; | 21 import android.content.SharedPreferences; |
| 22 import android.net.ConnectivityManager; | |
| 23 import android.util.Log; | 22 import android.util.Log; |
| 24 | 23 |
| 25 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback; | |
| 26 import org.adblockplus.libadblockplus.android.AdblockEngine; | 24 import org.adblockplus.libadblockplus.android.AdblockEngine; |
| 27 import org.adblockplus.libadblockplus.android.AndroidWebRequestResourceWrapper; | 25 import org.adblockplus.libadblockplus.android.AdblockEngineProvider; |
| 26 import org.adblockplus.libadblockplus.android.SingleInstanceEngineProvider; | |
| 28 import org.adblockplus.libadblockplus.android.Utils; | 27 import org.adblockplus.libadblockplus.android.Utils; |
| 29 | 28 |
| 30 import java.util.Map; | |
| 31 import java.util.concurrent.CountDownLatch; | |
| 32 import java.util.concurrent.atomic.AtomicInteger; | |
| 33 | |
| 34 /** | 29 /** |
| 35 * AdblockHelper shared resources | 30 * AdblockHelper shared resources |
| 36 * (singleton) | 31 * (singleton) |
| 37 */ | 32 */ |
| 38 public class AdblockHelper | 33 public class AdblockHelper |
| 39 { | 34 { |
| 40 private static final String TAG = Utils.getTag(AdblockHelper.class); | 35 private static final String TAG = Utils.getTag(AdblockHelper.class); |
| 41 | 36 |
| 42 /** | 37 /** |
| 43 * Suggested preference name to store settings | 38 * Suggested preference name to store settings |
| 44 */ | 39 */ |
| 45 public static final String PREFERENCE_NAME = "ADBLOCK"; | 40 public static final String PREFERENCE_NAME = "ADBLOCK"; |
| 46 | 41 |
| 47 /** | 42 /** |
| 48 * Suggested preference name to store intercepted subscription requests | 43 * Suggested preference name to store intercepted subscription requests |
| 49 */ | 44 */ |
| 50 public static final String PRELOAD_PREFERENCE_NAME = "ADBLOCK_PRELOAD"; | 45 public static final String PRELOAD_PREFERENCE_NAME = "ADBLOCK_PRELOAD"; |
| 51 private static AdblockHelper _instance; | 46 private static AdblockHelper _instance; |
| 52 | 47 |
| 53 private Context context; | 48 private SingleInstanceEngineProvider provider; |
| 54 private String basePath; | |
| 55 private boolean developmentBuild; | |
| 56 private String settingsPreferenceName; | |
| 57 private String preloadedPreferenceName; | |
| 58 private Map<String, Integer> urlToResourceIdMap; | |
| 59 private AdblockEngine engine; | |
| 60 private AdblockSettingsStorage storage; | 49 private AdblockSettingsStorage storage; |
| 61 private CountDownLatch engineCreated; | |
| 62 private Long v8IsolateProviderPtr; | |
| 63 | 50 |
| 64 /* | 51 private Runnable engineCreatedCallback = new Runnable() |
|
diegocarloslima
2018/01/19 12:17:45
maybe declare it final?
anton
2018/01/19 12:27:01
Acknowledged.
| |
| 65 Simple ARC management for AdblockEngine | 52 { |
| 66 Use `retain` and `release` | 53 @Override |
| 67 */ | 54 public void run() |
| 55 { | |
| 56 AdblockSettings settings = storage.load(); | |
| 57 if (settings != null) | |
| 58 { | |
| 59 Log.d(TAG, "Applying saved adblock settings to adblock engine"); | |
| 60 // apply last saved settings to adblock engine | |
| 68 | 61 |
|
jens
2018/01/19 09:54:44
Do wen need that empty line?
anton
2018/01/19 10:15:10
it's just [optional] separation between comments (
jens
2018/01/19 10:22:43
I would say that's up to you. I was just not sure
diegocarloslima
2018/01/19 12:17:46
for me it looks a bit weird this new line between
anton
2018/01/19 12:27:01
Acknowledged.
| |
| 69 private AtomicInteger referenceCounter = new AtomicInteger(0); | 62 // all the settings except `enabled` and whitelisted domains list |
| 63 // are saved by adblock engine itself | |
| 64 provider.getEngine().setEnabled(settings.isAdblockEnabled()); | |
| 65 provider.getEngine().setWhitelistedDomains(settings.getWhitelistedDomain s()); | |
| 66 | |
| 67 // allowed connection type is saved by filter engine but we need to over ride it | |
| 68 // as filter engine can be not created when changing | |
| 69 String connectionType = (settings.getAllowedConnectionType() != null | |
| 70 ? settings.getAllowedConnectionType().getValue() | |
| 71 : null); | |
| 72 provider.getEngine().getFilterEngine().setAllowedConnectionType(connecti onType); | |
| 73 } | |
| 74 else | |
| 75 { | |
| 76 Log.w(TAG, "No saved adblock settings"); | |
| 77 } | |
| 78 } | |
| 79 }; | |
| 80 | |
| 81 private Runnable engineDisposedCallback = new Runnable() | |
|
diegocarloslima
2018/01/19 12:17:46
maybe declare it final?
anton
2018/01/19 12:27:01
Acknowledged.
| |
| 82 { | |
| 83 @Override | |
| 84 public void run() | |
| 85 { | |
| 86 Log.d(TAG, "Releasing adblock settings storage"); | |
| 87 storage = null; | |
| 88 } | |
| 89 }; | |
| 70 | 90 |
| 71 // singleton | 91 // singleton |
| 72 protected AdblockHelper() | 92 protected AdblockHelper() |
| 73 { | 93 { |
| 74 // prevents instantiation | 94 // prevents instantiation |
| 75 } | 95 } |
| 76 | 96 |
| 77 /** | 97 /** |
| 78 * Use to get AdblockHelper instance | 98 * Use to get AdblockHelper instance |
| 79 * @return adblock instance | 99 * @return adblock instance |
| 80 */ | 100 */ |
| 81 public static synchronized AdblockHelper get() | 101 public static synchronized AdblockHelper get() |
| 82 { | 102 { |
| 83 if (_instance == null) | 103 if (_instance == null) |
| 84 { | 104 { |
| 85 _instance = new AdblockHelper(); | 105 _instance = new AdblockHelper(); |
| 86 } | 106 } |
| 87 | 107 |
| 88 return _instance; | 108 return _instance; |
| 89 } | 109 } |
| 90 | 110 |
| 91 public AdblockEngine getEngine() | 111 public AdblockEngineProvider getProvider() |
| 92 { | 112 { |
| 93 return engine; | 113 if (provider == null) |
| 114 { | |
| 115 throw new IllegalStateException("Usage exception: call init(...) first"); | |
| 116 } | |
| 117 return provider; | |
| 94 } | 118 } |
| 95 | 119 |
| 96 public AdblockSettingsStorage getStorage() | 120 public AdblockSettingsStorage getStorage() |
| 97 { | 121 { |
| 122 if (storage == null) | |
| 123 { | |
| 124 throw new IllegalStateException("Usage exception: call init(...) first"); | |
| 125 } | |
| 98 return storage; | 126 return storage; |
| 99 } | 127 } |
| 100 | 128 |
| 101 /** | 129 /** |
| 102 * Init with context | 130 * Init with context |
| 103 * @param context application context | 131 * @param context application context |
| 104 * @param basePath file system root to store files | 132 * @param basePath file system root to store files |
| 105 * | 133 * |
| 106 * Adblock Plus library will download subscription files and s tore them on | 134 * Adblock Plus library will download subscription files and s tore them on |
| 107 * the path passed. The path should exist and the directory co ntent should not be | 135 * the path passed. The path should exist and the directory co ntent should not be |
| 108 * cleared out occasionally. Using `context.getCacheDir().getA bsolutePath()` is not | 136 * cleared out occasionally. Using `context.getCacheDir().getA bsolutePath()` is not |
| 109 * recommended because it can be cleared by the system. | 137 * recommended because it can be cleared by the system. |
| 110 * @param developmentBuild debug or release? | 138 * @param developmentBuild debug or release? |
| 111 * @param preferenceName Shared Preferences name to store adblock settings | 139 * @param preferenceName Shared Preferences name to store adblock settings |
| 112 */ | 140 */ |
| 113 public AdblockHelper init(Context context, String basePath, | 141 public SingleInstanceEngineProvider init(Context context, String basePath, |
| 114 boolean developmentBuild, String preferenceName) | 142 boolean developmentBuild, String pref erenceName) |
| 115 { | 143 { |
| 116 this.context = context.getApplicationContext(); | 144 initProvider(context, basePath, developmentBuild); |
| 117 this.basePath = basePath; | 145 initStorage(context, preferenceName); |
| 118 this.developmentBuild = developmentBuild; | 146 return provider; |
| 119 this.settingsPreferenceName = preferenceName; | |
| 120 return this; | |
| 121 } | 147 } |
| 122 | 148 |
| 123 /** | 149 private void initProvider(Context context, String basePath, boolean developmen tBuild) |
| 124 * Use preloaded subscriptions | |
| 125 * @param preferenceName Shared Preferences name to store intercepted requests stats | |
| 126 * @param urlToResourceIdMap | |
| 127 */ | |
| 128 public AdblockHelper preloadSubscriptions(String preferenceName, Map<String, I nteger> urlToResourceIdMap) | |
| 129 { | 150 { |
| 130 this.preloadedPreferenceName = preferenceName; | 151 provider = new SingleInstanceEngineProvider(context, basePath, developmentBu ild); |
| 131 this.urlToResourceIdMap = urlToResourceIdMap; | 152 provider.setEngineCreatedCallback(engineCreatedCallback); |
| 132 return this; | 153 provider.setEngineDisposedCallback(engineDisposedCallback); |
| 133 } | 154 } |
| 134 | 155 |
| 135 public AdblockHelper useV8IsolateProvider(long ptr) | 156 private void initStorage(Context context, String settingsPreferenceName) |
| 136 { | 157 { |
| 137 this.v8IsolateProviderPtr = ptr; | |
| 138 return this; | |
| 139 } | |
| 140 | |
| 141 private void createAdblock() | |
| 142 { | |
| 143 ConnectivityManager connectivityManager = | |
| 144 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVIC E); | |
| 145 IsAllowedConnectionCallback isAllowedConnectionCallback = new IsAllowedConne ctionCallbackImpl(connectivityManager); | |
| 146 | |
| 147 Log.d(TAG, "Creating adblock engine ..."); | |
| 148 | |
| 149 // read and apply current settings | 158 // read and apply current settings |
| 150 SharedPreferences settingsPrefs = context.getSharedPreferences( | 159 SharedPreferences settingsPrefs = context.getSharedPreferences( |
| 151 settingsPreferenceName, | 160 settingsPreferenceName, |
| 152 Context.MODE_PRIVATE); | 161 Context.MODE_PRIVATE); |
| 162 | |
| 153 storage = new SharedPrefsStorage(settingsPrefs); | 163 storage = new SharedPrefsStorage(settingsPrefs); |
| 154 | |
| 155 AdblockEngine.Builder builder = AdblockEngine | |
| 156 .builder( | |
| 157 AdblockEngine.generateAppInfo(context, developmentBuild), | |
| 158 basePath) | |
| 159 .setIsAllowedConnectionCallback(isAllowedConnectionCallback) | |
| 160 .enableElementHiding(true); | |
| 161 | |
| 162 if (v8IsolateProviderPtr != null) | |
| 163 { | |
| 164 builder.useV8IsolateProvider(v8IsolateProviderPtr); | |
| 165 } | |
| 166 | |
| 167 // if preloaded subscriptions provided | |
| 168 if (preloadedPreferenceName != null) | |
| 169 { | |
| 170 SharedPreferences preloadedSubscriptionsPrefs = context.getSharedPreferenc es( | |
| 171 preloadedPreferenceName, | |
| 172 Context.MODE_PRIVATE); | |
| 173 builder.preloadSubscriptions( | |
| 174 context, | |
| 175 urlToResourceIdMap, | |
| 176 new AndroidWebRequestResourceWrapper.SharedPrefsStorage(preloadedSubscri ptionsPrefs)); | |
| 177 } | |
| 178 | |
| 179 engine = builder.build(); | |
| 180 | |
| 181 Log.d(TAG, "AdblockHelper engine created"); | |
| 182 | |
| 183 AdblockSettings settings = storage.load(); | |
| 184 if (settings != null) | |
| 185 { | |
| 186 Log.d(TAG, "Applying saved adblock settings to adblock engine"); | |
| 187 // apply last saved settings to adblock engine | |
| 188 | |
| 189 // all the settings except `enabled` and whitelisted domains list | |
| 190 // are saved by adblock engine itself | |
| 191 engine.setEnabled(settings.isAdblockEnabled()); | |
| 192 engine.setWhitelistedDomains(settings.getWhitelistedDomains()); | |
| 193 | |
| 194 // allowed connection type is saved by filter engine but we need to overri de it | |
| 195 // as filter engine can be not created when changing | |
| 196 String connectionType = (settings.getAllowedConnectionType() != null | |
| 197 ? settings.getAllowedConnectionType().getValue() | |
| 198 : null); | |
| 199 engine.getFilterEngine().setAllowedConnectionType(connectionType); | |
| 200 } | |
| 201 else | |
| 202 { | |
| 203 Log.w(TAG, "No saved adblock settings"); | |
| 204 } | |
| 205 } | 164 } |
| 206 | 165 |
| 207 /** | 166 // The methods below are deprecated: use .getProvider().method() instead |
|
diegocarloslima
2018/01/19 12:17:45
This comment would be better inside the javadoc pa
anton
2018/01/19 12:27:01
Acknowledged.
| |
| 208 * Wait until everything is ready (used for `retain(true)`) | 167 |
| 209 * Warning: locks current thread | 168 @Deprecated |
| 210 */ | 169 public boolean retain(boolean asynchronous) |
| 170 { | |
| 171 return provider.retain(asynchronous); | |
| 172 } | |
| 173 | |
| 174 @Deprecated | |
| 211 public void waitForReady() | 175 public void waitForReady() |
| 212 { | 176 { |
| 213 if (engineCreated == null) | 177 provider.waitForReady(); |
| 214 { | |
| 215 throw new RuntimeException("AdblockHelper Plus usage exception: call retai n(true) first"); | |
| 216 } | |
| 217 | |
| 218 try | |
| 219 { | |
| 220 Log.d(TAG, "Waiting for ready ..."); | |
| 221 engineCreated.await(); | |
| 222 Log.d(TAG, "Ready"); | |
| 223 } | |
| 224 catch (InterruptedException e) | |
| 225 { | |
| 226 Log.w(TAG, "Interrupted", e); | |
| 227 } | |
| 228 } | 178 } |
| 229 | 179 |
| 230 private void disposeAdblock() | 180 @Deprecated |
| 181 public AdblockEngine getEngine() | |
| 231 { | 182 { |
| 232 Log.w(TAG, "Disposing adblock engine"); | 183 return provider.getEngine(); |
| 233 | |
| 234 engine.dispose(); | |
| 235 engine = null; | |
| 236 | |
| 237 storage = null; | |
| 238 } | 184 } |
| 239 | 185 |
| 240 /** | 186 @Deprecated |
| 241 * Get registered clients count | 187 public boolean release() |
| 242 * @return registered clients count | 188 { |
| 243 */ | 189 return provider.release(); |
| 190 } | |
| 191 | |
| 192 @Deprecated | |
| 244 public int getCounter() | 193 public int getCounter() |
| 245 { | 194 { |
| 246 return referenceCounter.get(); | 195 return provider.getCounter(); |
| 247 } | |
| 248 | |
| 249 /** | |
| 250 * Register AdblockHelper engine client | |
| 251 * @param asynchronous If `true` engines will be created in background thread without locking of | |
| 252 * current thread. Use waitForReady() before getEngine() l ater. | |
| 253 * If `false` locks current thread. | |
| 254 * @return if a new instance is allocated | |
| 255 */ | |
| 256 public synchronized boolean retain(boolean asynchronous) | |
| 257 { | |
| 258 boolean firstInstance = false; | |
| 259 | |
| 260 if (referenceCounter.getAndIncrement() == 0) | |
| 261 { | |
| 262 firstInstance = true; | |
| 263 | |
| 264 if (!asynchronous) | |
| 265 { | |
| 266 createAdblock(); | |
| 267 } | |
| 268 else | |
| 269 { | |
| 270 // latch is required for async (see `waitForReady()`) | |
| 271 engineCreated = new CountDownLatch(1); | |
| 272 | |
| 273 new Thread(new Runnable() | |
| 274 { | |
| 275 @Override | |
| 276 public void run() | |
| 277 { | |
| 278 createAdblock(); | |
| 279 | |
| 280 // unlock waiting client thread | |
| 281 engineCreated.countDown(); | |
| 282 } | |
| 283 }).start(); | |
| 284 } | |
| 285 } | |
| 286 return firstInstance; | |
| 287 } | |
| 288 | |
| 289 /** | |
| 290 * Unregister AdblockHelper engine client | |
| 291 * @return `true` if the last instance is destroyed | |
| 292 */ | |
| 293 public synchronized boolean release() | |
| 294 { | |
| 295 boolean lastInstance = false; | |
| 296 | |
| 297 if (referenceCounter.decrementAndGet() == 0) | |
| 298 { | |
| 299 lastInstance = true; | |
| 300 | |
| 301 if (engineCreated != null) | |
| 302 { | |
| 303 // retained asynchronously | |
| 304 waitForReady(); | |
| 305 disposeAdblock(); | |
| 306 | |
| 307 // to unlock waiting client in waitForReady() | |
| 308 engineCreated.countDown(); | |
| 309 engineCreated = null; | |
| 310 } | |
| 311 else | |
| 312 { | |
| 313 disposeAdblock(); | |
| 314 } | |
| 315 } | |
| 316 return lastInstance; | |
| 317 } | 196 } |
| 318 } | 197 } |
| OLD | NEW |