Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: mobile/android/thirdparty/org/adblockplus/browser/AddOnBridge.java

Issue 29350065: Issue 2853 - Settings changes are sometimes not saved if the user quits the app (Closed)
Left Patch Set: Adjusting spacing and also adding code change comment Created Nov. 2, 2016, 11:28 a.m.
Right Patch Set: Renaming 'uncompleted' to 'pending' Created Jan. 31, 2017, 8 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « mobile/android/base/GeckoApplication.java ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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";
Felix Dahlke 2016/12/13 11:25:10 I'm a bit confused as to what the point of all thi
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)
Felix Dahlke 2016/12/13 11:25:10 It makes me a bit nervous to rely on outside code
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()
Felix Dahlke 2016/12/13 11:25:10 Does this have to be public? But see my suggestion
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())
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()
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
161 public void run()
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<>();
192 if (jsonString == null) 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)
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld