Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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.browser; | 18 package org.adblockplus.browser; |
19 | 19 |
20 import java.util.ArrayList; | 20 import java.util.ArrayList; |
21 import java.util.HashMap; | 21 import java.util.HashMap; |
22 import java.util.List; | 22 import java.util.List; |
23 import java.util.Map; | 23 import java.util.Map; |
24 import java.util.concurrent.Semaphore; | |
25 | 24 |
26 import android.annotation.SuppressLint; | 25 import android.annotation.SuppressLint; |
27 import android.content.Context; | 26 import android.content.Context; |
28 import android.content.SharedPreferences; | 27 import android.content.SharedPreferences; |
29 import android.os.Handler; | 28 import android.os.Handler; |
30 import android.os.HandlerThread; | 29 import android.os.HandlerThread; |
31 import android.util.Log; | 30 import android.util.Log; |
32 | 31 |
33 import org.json.JSONArray; | 32 import org.json.JSONArray; |
34 import org.json.JSONException; | 33 import org.json.JSONException; |
35 import org.json.JSONObject; | 34 import org.json.JSONObject; |
35 import org.mozilla.gecko.EventDispatcher; | |
36 import org.mozilla.gecko.GeckoAppShell; | 36 import org.mozilla.gecko.GeckoAppShell; |
37 import org.mozilla.gecko.util.GeckoEventListener; | |
37 import org.mozilla.gecko.util.GeckoRequest; | 38 import org.mozilla.gecko.util.GeckoRequest; |
38 import org.mozilla.gecko.util.NativeJSObject; | 39 import org.mozilla.gecko.util.NativeJSObject; |
39 | 40 |
40 @SuppressLint("DefaultLocale") | 41 @SuppressLint("DefaultLocale") |
41 public class AddOnBridge | 42 public class AddOnBridge |
42 { | 43 { |
43 private static final String TAG = "AdblockBrowser.AddOnBridge"; | 44 private static final String TAG = "AdblockBrowser.AddOnBridge"; |
44 private static final String REQUEST_NAME = "AdblockPlus:Api"; | 45 private static final String REQUEST_NAME = "AdblockPlus:Api"; |
45 // Timeout for checking filter loading (in seconds) | |
46 private static final int QUERY_GET_FILTERS_LOADED_TIMEOUT = 30; | |
47 // How long to wait between retries (in milliseconds) | |
48 private static final int QUERY_GET_FILTERS_LOADED_DELAY = 500; | |
49 // Handler+HandlerThread for posting delayed re-tries without interfering with | 46 // Handler+HandlerThread for posting delayed re-tries without interfering with |
50 // other threads (e.g. the UI or Gecko thread) | 47 // other threads (e.g. the UI or Gecko thread) |
51 private static final HandlerThread PRIVATE_HANDLER_THREAD; | 48 private static final HandlerThread PRIVATE_HANDLER_THREAD; |
52 private static final Handler PRIVATE_HANDLER; | 49 private static final Handler PRIVATE_HANDLER; |
53 // Global handler, for e.g. UI tasks | 50 // Global handler, for e.g. UI tasks |
54 private static final HandlerThread GLOBAL_HANDLER_THREAD; | 51 private static final HandlerThread GLOBAL_HANDLER_THREAD; |
55 private static final Handler GLOBAL_HANDLER; | 52 private static final Handler GLOBAL_HANDLER; |
56 // Static members for syncing requests that might not have been saved by filte r storage | 53 // Sometimes, the app is killed before the extension is able to save all chang es regarding |
54 // AddOnBridge requests. Given that, we need to store the pending requests on SharedPrefs, | |
55 // so we can resend them to the extension once the app restarts | |
57 // See https://issues.adblockplus.org/ticket/2853 | 56 // See https://issues.adblockplus.org/ticket/2853 |
58 private static final Semaphore SYNC_REQUESTS_SEMAPHORE = new Semaphore(1); | 57 private static final AddOnEventListener ADD_ON_EVENT_LISTENER = new AddOnEvent Listener(); |
59 private static final int SYNC_REQUESTS_DELAY = 30 * 1000; | 58 private static final String ON_FILTERS_LOAD_EVENT = "Abb:OnFiltersLoad"; |
60 private static final List<ChainedRequest> PENDING_SYNC_REQUESTS = new ArrayLis t<>(); | 59 private static final String ON_FILTERS_SAVE_EVENT = "Abb:OnFiltersSave"; |
61 private static final String PENDING_SYNC_REQUESTS_KEY = "PENDING_SYNC_REQUESTS _KEY"; | 60 private static final List<AddOnRequest> PENDING_REQUESTS = new ArrayList<>(); |
61 private static final String PENDING_REQUESTS_PREFS_KEY = "PENDING_REQUESTS_PRE FS_KEY"; | |
62 | 62 |
63 private static SharedPreferences sharedPrefs; | 63 private static SharedPreferences sharedPrefs; |
64 private static boolean filtersLoaded; | |
64 | 65 |
65 static | 66 static |
66 { | 67 { |
67 PRIVATE_HANDLER_THREAD = new HandlerThread("abp-private-handler"); | 68 PRIVATE_HANDLER_THREAD = new HandlerThread("abp-private-handler"); |
68 PRIVATE_HANDLER_THREAD.setDaemon(true); | 69 PRIVATE_HANDLER_THREAD.setDaemon(true); |
69 PRIVATE_HANDLER_THREAD.start(); | 70 PRIVATE_HANDLER_THREAD.start(); |
70 PRIVATE_HANDLER = new Handler(PRIVATE_HANDLER_THREAD.getLooper()); | 71 PRIVATE_HANDLER = new Handler(PRIVATE_HANDLER_THREAD.getLooper()); |
71 | 72 |
72 GLOBAL_HANDLER_THREAD = new HandlerThread("abp-global-handler"); | 73 GLOBAL_HANDLER_THREAD = new HandlerThread("abp-global-handler"); |
73 GLOBAL_HANDLER_THREAD.setDaemon(true); | 74 GLOBAL_HANDLER_THREAD.setDaemon(true); |
74 GLOBAL_HANDLER_THREAD.start(); | 75 GLOBAL_HANDLER_THREAD.start(); |
75 GLOBAL_HANDLER = new Handler(GLOBAL_HANDLER_THREAD.getLooper()); | 76 GLOBAL_HANDLER = new Handler(GLOBAL_HANDLER_THREAD.getLooper()); |
76 } | 77 } |
77 | 78 |
78 public static void init(Context context) | 79 public static void init(Context context) |
79 { | 80 { |
80 sharedPrefs = context.getSharedPreferences(AddOnBridge.class.getName(), Cont ext.MODE_PRIVATE); | 81 sharedPrefs = context.getSharedPreferences(AddOnBridge.class.getName(), Cont ext.MODE_PRIVATE); |
81 startSyncRequests(); | 82 EventDispatcher.getInstance().registerGeckoThreadListener(ADD_ON_EVENT_LISTE NER, ON_FILTERS_LOAD_EVENT, ON_FILTERS_SAVE_EVENT); |
83 loadPendingRequests(); | |
82 } | 84 } |
83 | 85 |
84 public static void postToHandler(Runnable runnable) | 86 public static void postToHandler(Runnable runnable) |
85 { | 87 { |
86 GLOBAL_HANDLER.post(runnable); | 88 GLOBAL_HANDLER.post(runnable); |
87 } | 89 } |
88 | 90 |
89 public static void postToHandlerDelayed(Runnable runnable, long delayMillis) | 91 public static void postToHandlerDelayed(Runnable runnable, long delayMillis) |
90 { | 92 { |
91 GLOBAL_HANDLER.postDelayed(runnable, delayMillis); | 93 GLOBAL_HANDLER.postDelayed(runnable, delayMillis); |
92 } | 94 } |
93 | 95 |
94 public static void startSyncRequests() | 96 private static void loadPendingRequests() |
95 { | 97 { |
96 postToHandler(new Runnable() | 98 PRIVATE_HANDLER.post(new Runnable() |
97 { | 99 { |
98 @Override | 100 @Override |
99 public void run() | 101 public void run() |
100 { | 102 { |
101 SYNC_REQUESTS_SEMAPHORE.acquireUninterruptibly(); | 103 final String jsonString = sharedPrefs.getString(PENDING_REQUESTS_PREFS_K EY, null); |
102 final String jsonString = sharedPrefs.getString(PENDING_SYNC_REQUESTS_KE Y, null); | 104 PENDING_REQUESTS.addAll(0, jsonStringToRequestList(jsonString)); |
103 PENDING_SYNC_REQUESTS.clear(); | |
104 PENDING_SYNC_REQUESTS.addAll(jsonStringToRequestList(jsonString)); | |
105 for(final ChainedRequest request : PENDING_SYNC_REQUESTS) | |
106 { | |
107 GeckoAppShell.sendRequestToGecko(request); | |
108 } | |
109 SYNC_REQUESTS_SEMAPHORE.release(); | |
110 performSyncRequests(); | |
111 } | 105 } |
112 }); | 106 }); |
113 } | 107 } |
114 | 108 |
115 private static void performSyncRequests() | 109 private static void sendOrEnqueueRequest(final AddOnRequest request) |
116 { | 110 { |
117 SYNC_REQUESTS_SEMAPHORE.acquireUninterruptibly(); | 111 PRIVATE_HANDLER.post(new Runnable() |
118 if(PENDING_SYNC_REQUESTS.isEmpty()) | |
anton
2016/09/30 06:51:03
space here?
diegocarloslima
2016/10/26 13:48:04
Acknowledged.
| |
119 { | |
120 SYNC_REQUESTS_SEMAPHORE.release(); | |
121 scheduleSyncRequests(); | |
122 return; | |
123 } | |
124 queryValue(new AdblockPlusApiCallback() | |
125 { | |
126 @Override | |
127 public void onApiRequestSucceeded(NativeJSObject jsObject) | |
128 { | |
129 final boolean requestsSaved = AddOnBridge.getBooleanFromJsObject(jsObjec t, "value", false); | |
130 if (requestsSaved) | |
131 { | |
132 PENDING_SYNC_REQUESTS.clear(); | |
133 storeStringPref(PENDING_SYNC_REQUESTS_KEY, requestListToJsonString(PEN DING_SYNC_REQUESTS)); | |
134 } | |
135 SYNC_REQUESTS_SEMAPHORE.release(); | |
136 scheduleSyncRequests(); | |
137 } | |
138 | |
139 @Override | |
140 public void onApiRequestFailed(String errorMessage) | |
141 { | |
142 SYNC_REQUESTS_SEMAPHORE.release(); | |
143 scheduleSyncRequests(); | |
144 } | |
145 }, "requestsSaved"); | |
146 } | |
147 | |
148 private static void scheduleSyncRequests() | |
149 { | |
150 postToHandlerDelayed(new Runnable() | |
151 { | 112 { |
152 @Override | 113 @Override |
153 public void run() | 114 public void run() |
154 { | 115 { |
155 performSyncRequests(); | 116 if (!filtersLoaded) |
156 } | 117 { |
157 }, SYNC_REQUESTS_DELAY); | 118 PENDING_REQUESTS.add(request); |
158 } | 119 } |
159 | 120 else |
160 private static void addPendingSyncRequest(final ChainedRequest chainedRequest) | 121 { |
161 { | 122 GeckoAppShell.sendRequestToGecko(request); |
162 postToHandler(new Runnable() | 123 } |
124 } | |
125 }); | |
126 } | |
127 | |
128 private static void sendPendingRequests() | |
129 { | |
130 PRIVATE_HANDLER.post(new Runnable() | |
163 { | 131 { |
164 @Override | 132 @Override |
165 public void run() | 133 public void run() |
166 { | 134 { |
167 SYNC_REQUESTS_SEMAPHORE.acquireUninterruptibly(); | 135 for (final AddOnRequest request : PENDING_REQUESTS) |
168 PENDING_SYNC_REQUESTS.add(chainedRequest); | 136 { |
169 storeStringPref(PENDING_SYNC_REQUESTS_KEY, requestListToJsonString(PENDI NG_SYNC_REQUESTS)); | 137 GeckoAppShell.sendRequestToGecko(request); |
170 SYNC_REQUESTS_SEMAPHORE.release(); | 138 } |
139 PENDING_REQUESTS.clear(); | |
171 } | 140 } |
172 }); | 141 }); |
173 } | 142 } |
174 | 143 |
175 private static String requestListToJsonString(final List<ChainedRequest> reque stList) | 144 private static void clearPendingRequests() |
176 { | 145 { |
177 if(requestList == null) | 146 PRIVATE_HANDLER.post(new Runnable() |
anton
2016/09/30 06:51:03
space here?
diegocarloslima
2016/10/26 13:48:04
Acknowledged.
| |
178 { | 147 { |
179 return null; | 148 @Override |
180 } | 149 public void run() |
181 final JSONArray jsonArray = new JSONArray(); | 150 { |
182 for (final ChainedRequest request : requestList) | 151 storeStringPref(PENDING_REQUESTS_PREFS_KEY, null); |
183 { | 152 } |
184 jsonArray.put(request.value); | 153 }); |
185 } | 154 } |
186 return jsonArray.toString(); | 155 |
187 } | 156 private static void storePendingRequest(final AddOnRequest request) |
188 | 157 { |
189 private static List<ChainedRequest> jsonStringToRequestList(final String jsonS tring) | 158 PRIVATE_HANDLER.post(new Runnable() |
190 { | 159 { |
191 final List<ChainedRequest> requestList = new ArrayList<>(); | 160 @Override |
192 if(jsonString == null) | 161 public void run() |
anton
2016/09/30 06:51:03
space here?
diegocarloslima
2016/10/26 13:48:04
Acknowledged.
| |
162 { | |
163 final String jsonString = sharedPrefs.getString(PENDING_REQUESTS_PREFS_K EY, null); | |
164 try | |
165 { | |
166 final JSONArray jsonArray = jsonString != null ? new JSONArray(jsonStr ing) : new JSONArray(); | |
167 jsonArray.put(request.value); | |
168 storeStringPref(PENDING_REQUESTS_PREFS_KEY, jsonArray.toString()); | |
169 } | |
170 catch (JSONException e) | |
171 { | |
172 Log.e(TAG, "Failed to store pending request with error: " + e.getMessa ge(), e); | |
173 } | |
174 } | |
175 }); | |
176 } | |
177 | |
178 private static List<AddOnRequest> jsonStringToRequestList(final String jsonStr ing) | |
179 { | |
180 final List<AddOnRequest> requestList = new ArrayList<>(); | |
181 if (jsonString == null) | |
193 { | 182 { |
194 return requestList; | 183 return requestList; |
195 } | 184 } |
196 try | 185 try |
197 { | 186 { |
198 final JSONArray jsonArray = new JSONArray(jsonString); | 187 final JSONArray jsonArray = new JSONArray(jsonString); |
199 for(int i = 0; i < jsonArray.length(); i++) | 188 for (int i = 0; i < jsonArray.length(); i++) |
200 { | 189 { |
201 final ChainedRequest request = new ChainedRequest(jsonArray.getJSONObjec t(i), null); | 190 final AddOnRequest request = new AddOnRequest(jsonArray.getJSONObject(i) , null); |
202 requestList.add(request); | 191 requestList.add(request); |
203 } | 192 } |
204 } | 193 } |
205 catch (JSONException e) | 194 catch (JSONException e) |
anton
2016/09/30 06:51:03
Was ignoring of thrown exception done intentionall
diegocarloslima
2016/10/26 13:48:04
Yes it was done intentionally, to handle gracefull
| |
206 { | 195 { |
196 Log.e(TAG, "Failed to parse json to request list with error: " + e.getMess age(), e); | |
207 } | 197 } |
208 return requestList; | 198 return requestList; |
209 } | 199 } |
210 | 200 |
211 private static void storeStringPref(String key, String value) | 201 private static void storeStringPref(String key, String value) |
212 { | 202 { |
213 final SharedPreferences.Editor editor = sharedPrefs.edit(); | 203 final SharedPreferences.Editor editor = sharedPrefs.edit(); |
214 editor.putString(key, value); | 204 editor.putString(key, value); |
215 editor.commit(); | 205 editor.commit(); |
216 } | 206 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 if (Character.isUpperCase(str.charAt(0))) | 266 if (Character.isUpperCase(str.charAt(0))) |
277 { | 267 { |
278 return str; | 268 return str; |
279 } | 269 } |
280 return Character.toString(Character.toUpperCase(str.charAt(0))) + str.substr ing(1); | 270 return Character.toString(Character.toUpperCase(str.charAt(0))) + str.substr ing(1); |
281 } | 271 } |
282 | 272 |
283 public static void queryValue(final AdblockPlusApiCallback callback, final Str ing name) | 273 public static void queryValue(final AdblockPlusApiCallback callback, final Str ing name) |
284 { | 274 { |
285 Log.d(TAG, "queryValue for " + name); | 275 Log.d(TAG, "queryValue for " + name); |
286 GeckoAppShell.sendRequestToGecko( | 276 final AddOnRequest request = |
287 new ChainedRequest( | 277 new AddOnRequest(createRequestData("get" + makeFirstCharacterUppercase(n ame)), callback); |
288 createRequestData("get" + makeFirstCharacterUppercase(name)), | 278 sendOrEnqueueRequest(request); |
289 callback)); | |
290 } | 279 } |
291 | 280 |
292 public static void setBoolean(final AdblockPlusApiCallback callback, final Str ing name, | 281 public static void setBoolean(final AdblockPlusApiCallback callback, final Str ing name, |
293 final boolean enable) | 282 final boolean enable) |
294 { | 283 { |
295 Log.d(TAG, "setBoolean " + enable + " for " + name); | 284 Log.d(TAG, "setBoolean " + enable + " for " + name); |
296 final ChainedRequest request = new ChainedRequest(createRequestData("set" + makeFirstCharacterUppercase(name), enable), callback); | 285 final AddOnRequest request = |
297 GeckoAppShell.sendRequestToGecko(request); | 286 new AddOnRequest(createRequestData("set" + makeFirstCharacterUppercase(n ame), enable), callback); |
298 addPendingSyncRequest(request); | 287 sendOrEnqueueRequest(request); |
288 storePendingRequest(request); | |
299 } | 289 } |
300 | 290 |
301 private static void callFunction(final AdblockPlusApiCallback callback, final String name, | 291 private static void callFunction(final AdblockPlusApiCallback callback, final String name, |
302 final Map<String, Object> parameters) | 292 final Map<String, Object> parameters) |
303 { | 293 { |
304 // By default, requests are not synced | 294 // By default, requests are not stored on the pending request prefs. This sh ould apply for |
295 // requests that doesn't result in save operations performed by the extensio n | |
305 callFunction(callback, name, parameters, false); | 296 callFunction(callback, name, parameters, false); |
306 } | 297 } |
307 | 298 |
308 private static void callFunction(final AdblockPlusApiCallback callback, final String name, | 299 private static void callFunction(final AdblockPlusApiCallback callback, final String name, |
309 final Map<String, Object> parameters, boolean shouldSyncRequest) | 300 final Map<String, Object> parameters, boolean resendIfAborted) |
310 { | 301 { |
311 final JSONObject requestData = createRequestData(name); | 302 final JSONObject requestData = createRequestData(name); |
312 try | 303 try |
313 { | 304 { |
314 for (Map.Entry<String, Object> entry : parameters.entrySet()) | 305 for (Map.Entry<String, Object> entry : parameters.entrySet()) |
306 { | |
315 requestData.put(entry.getKey(), entry.getValue()); | 307 requestData.put(entry.getKey(), entry.getValue()); |
308 } | |
316 } | 309 } |
317 catch (JSONException e) | 310 catch (JSONException e) |
318 { | 311 { |
319 // we're only adding sane objects | 312 // we're only adding sane objects |
320 Log.e(TAG, "Creating request data failed with: " + e.getMessage(), e); | 313 Log.e(TAG, "Creating request data failed with: " + e.getMessage(), e); |
321 } | 314 } |
322 final ChainedRequest request = new ChainedRequest(requestData, callback); | 315 final AddOnRequest request = new AddOnRequest(requestData, callback); |
323 GeckoAppShell.sendRequestToGecko(request); | 316 sendOrEnqueueRequest(request); |
324 if(shouldSyncRequest) | 317 if (resendIfAborted) |
325 { | 318 { |
326 addPendingSyncRequest(request); | 319 storePendingRequest(request); |
327 } | 320 } |
328 } | 321 } |
329 | 322 |
330 public static void querySubscriptionListStatus(final AdblockPlusApiCallback ca llback, | 323 public static void querySubscriptionListStatus(final AdblockPlusApiCallback ca llback, |
331 final String url) | 324 final String url) |
332 { | 325 { |
333 Log.d(TAG, "querySubscriptionListStatus for " + url); | 326 Log.d(TAG, "querySubscriptionListStatus for " + url); |
334 final Map<String, Object> parameters = new HashMap<String, Object>(); | 327 final Map<String, Object> parameters = new HashMap<String, Object>(); |
335 parameters.put("url", url); | 328 parameters.put("url", url); |
336 callFunction(callback, "isSubscriptionListed", parameters); | 329 callFunction(callback, "isSubscriptionListed", parameters); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 public static void whitelistSite(final AdblockPlusApiCallback callback, final String url, | 379 public static void whitelistSite(final AdblockPlusApiCallback callback, final String url, |
387 final boolean whitelisted) | 380 final boolean whitelisted) |
388 { | 381 { |
389 Log.d(TAG, "whitelistSite for " + url); | 382 Log.d(TAG, "whitelistSite for " + url); |
390 final Map<String, Object> parameters = new HashMap<String, Object>(); | 383 final Map<String, Object> parameters = new HashMap<String, Object>(); |
391 parameters.put("url", url); | 384 parameters.put("url", url); |
392 parameters.put("whitelisted", whitelisted); | 385 parameters.put("whitelisted", whitelisted); |
393 callFunction(callback, "whitelistSite", parameters, true); | 386 callFunction(callback, "whitelistSite", parameters, true); |
394 } | 387 } |
395 | 388 |
396 private static class ChainedRequest extends GeckoRequest | 389 private static class AddOnRequest extends GeckoRequest |
397 { | 390 { |
398 private final JSONObject value; | 391 private final JSONObject value; |
399 private final AdblockPlusApiCallback apiCallback; | 392 private final AdblockPlusApiCallback apiCallback; |
400 private final boolean checkForFiltersLoaded; | 393 |
401 private final long creationTime; | 394 AddOnRequest(final JSONObject value, final AdblockPlusApiCallback callback) |
402 | 395 { |
403 public ChainedRequest(final JSONObject value, final AdblockPlusApiCallback c allback, | 396 super(AddOnBridge.REQUEST_NAME, value); |
404 final boolean checkForFiltersLoaded, final long creationTime) | |
405 { | |
406 super(AddOnBridge.REQUEST_NAME, | |
407 checkForFiltersLoaded ? createRequestData("getFiltersLoaded") : value) ; | |
408 this.value = value; | 397 this.value = value; |
409 this.apiCallback = callback; | 398 this.apiCallback = callback; |
410 this.checkForFiltersLoaded = checkForFiltersLoaded; | |
411 this.creationTime = creationTime; | |
412 } | |
413 | |
414 public ChainedRequest(final JSONObject value, final AdblockPlusApiCallback c allback) | |
415 { | |
416 this(value, callback, true, System.currentTimeMillis()); | |
417 } | |
418 | |
419 public ChainedRequest cloneForRetry() | |
420 { | |
421 return new ChainedRequest(this.value, this.apiCallback, true, this.creatio nTime); | |
422 } | |
423 | |
424 public ChainedRequest cloneForRequest() | |
425 { | |
426 return new ChainedRequest(this.value, this.apiCallback, false, this.creati onTime); | |
427 } | 399 } |
428 | 400 |
429 private void invokeSuccessCallback(final NativeJSObject jsObject) | 401 private void invokeSuccessCallback(final NativeJSObject jsObject) |
430 { | 402 { |
431 try | 403 try |
432 { | 404 { |
433 if (this.apiCallback != null) | 405 if (this.apiCallback != null) |
434 { | 406 { |
435 this.apiCallback.onApiRequestSucceeded(jsObject); | 407 this.apiCallback.onApiRequestSucceeded(jsObject); |
436 } | 408 } |
437 } | 409 } |
438 catch (final Exception e) | 410 catch (final Exception e) |
439 { | 411 { |
440 Log.e(TAG, "onApiRequestSucceeded threw exception: " + e.getMessage(), e ); | 412 Log.e(TAG, "onApiRequestSucceeded threw exception: " + e.getMessage(), e ); |
441 } | 413 } |
442 } | 414 } |
443 | 415 |
444 private void invokeFailureCallback(final String msg) | 416 private void invokeFailureCallback(final String msg) |
445 { | 417 { |
446 if (this.apiCallback != null) | 418 if (this.apiCallback != null) |
447 { | 419 { |
448 this.apiCallback.onApiRequestFailed(msg); | 420 this.apiCallback.onApiRequestFailed(msg); |
449 } | 421 } |
450 } | 422 } |
451 | 423 |
452 private void invokeFailureCallback(final NativeJSObject jsObject) | 424 private void invokeFailureCallback(final NativeJSObject jsObject) |
453 { | 425 { |
454 invokeFailureCallback(getStringFromJsObject(jsObject, "error", "unknown er ror")); | 426 invokeFailureCallback(getStringFromJsObject(jsObject, "error", "unknown er ror")); |
455 } | |
456 | |
457 private void attemptRetry() | |
458 { | |
459 if (System.currentTimeMillis() - this.creationTime > (QUERY_GET_FILTERS_LO ADED_TIMEOUT * 1000)) | |
460 { | |
461 this.invokeFailureCallback("getFiltersLoaded timeout"); | |
462 } | |
463 else | |
464 { | |
465 Log.d(TAG, "Retrying: " + this.value); | |
466 final ChainedRequest next = this.cloneForRetry(); | |
467 PRIVATE_HANDLER.postDelayed(new Runnable() | |
468 { | |
469 @Override | |
470 public void run() | |
471 { | |
472 GeckoAppShell.sendRequestToGecko(next); | |
473 } | |
474 }, QUERY_GET_FILTERS_LOADED_DELAY); | |
475 } | |
476 } | 427 } |
477 | 428 |
478 @Override | 429 @Override |
479 public void onError(final NativeJSObject error) | 430 public void onError(final NativeJSObject error) |
480 { | 431 { |
481 if (this.checkForFiltersLoaded) | 432 this.invokeFailureCallback( |
482 { | 433 "GeckoRequest error: " + error.optString("message", "<no message>") + "\n" + |
483 this.attemptRetry(); | 434 error.optString("stack", "<no stack>")); |
484 } | |
485 else | |
486 { | |
487 this.invokeFailureCallback( | |
488 "GeckoRequest error: " + error.optString("message", "<no message>") + "\n" + | |
489 error.optString("stack", "<no stack>")); | |
490 } | |
491 } | 435 } |
492 | 436 |
493 @Override | 437 @Override |
494 public void onResponse(final NativeJSObject jsObject) | 438 public void onResponse(final NativeJSObject jsObject) |
495 { | 439 { |
496 if (this.checkForFiltersLoaded) | 440 if (getBooleanFromJsObject(jsObject, "success", false)) |
497 { | 441 { |
498 if (getBooleanFromJsObject(jsObject, "success", false) | 442 this.invokeSuccessCallback(jsObject); |
499 && getBooleanFromJsObject(jsObject, "value", false)) | |
500 { | |
501 GeckoAppShell.sendRequestToGecko(this.cloneForRequest()); | |
502 } | |
503 else | |
504 { | |
505 this.attemptRetry(); | |
506 } | |
507 } | 443 } |
508 else | 444 else |
509 { | 445 { |
510 if (getBooleanFromJsObject(jsObject, "success", false)) | 446 this.invokeFailureCallback(jsObject); |
511 { | 447 } |
512 this.invokeSuccessCallback(jsObject); | 448 } |
513 } | 449 } |
514 else | 450 |
515 { | 451 private static class AddOnEventListener implements GeckoEventListener |
516 this.invokeFailureCallback(jsObject); | 452 { |
517 } | 453 @Override |
454 public void handleMessage(String event, JSONObject message) | |
455 { | |
456 if (ON_FILTERS_LOAD_EVENT.equals(event)) | |
457 { | |
458 // The filters have been loaded by the extension. Given that, we can sen d all pending requests | |
459 filtersLoaded = true; | |
460 sendPendingRequests(); | |
461 } | |
462 else if (ON_FILTERS_SAVE_EVENT.equals(event)) | |
463 { | |
464 // All changes have been saved by the extension. That way, we can clear our list of | |
465 // pending requests | |
466 // See https://issues.adblockplus.org/ticket/2853 | |
467 clearPendingRequests(); | |
518 } | 468 } |
519 } | 469 } |
520 } | 470 } |
521 } | 471 } |
LEFT | RIGHT |