| 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-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.HashMap; | 21 import java.util.HashMap; | 
|  | 22 import java.util.List; | 
| 21 import java.util.Map; | 23 import java.util.Map; | 
| 22 | 24 | 
| 23 import android.annotation.SuppressLint; | 25 import android.annotation.SuppressLint; | 
|  | 26 import android.content.Context; | 
|  | 27 import android.content.SharedPreferences; | 
| 24 import android.os.Handler; | 28 import android.os.Handler; | 
| 25 import android.os.HandlerThread; | 29 import android.os.HandlerThread; | 
| 26 import android.util.Log; | 30 import android.util.Log; | 
| 27 | 31 | 
|  | 32 import org.json.JSONArray; | 
| 28 import org.json.JSONException; | 33 import org.json.JSONException; | 
| 29 import org.json.JSONObject; | 34 import org.json.JSONObject; | 
|  | 35 import org.mozilla.gecko.EventDispatcher; | 
| 30 import org.mozilla.gecko.GeckoAppShell; | 36 import org.mozilla.gecko.GeckoAppShell; | 
|  | 37 import org.mozilla.gecko.util.GeckoEventListener; | 
| 31 import org.mozilla.gecko.util.GeckoRequest; | 38 import org.mozilla.gecko.util.GeckoRequest; | 
| 32 import org.mozilla.gecko.util.NativeJSObject; | 39 import org.mozilla.gecko.util.NativeJSObject; | 
| 33 | 40 | 
| 34 @SuppressLint("DefaultLocale") | 41 @SuppressLint("DefaultLocale") | 
| 35 public class AddOnBridge | 42 public class AddOnBridge | 
| 36 { | 43 { | 
| 37   private static final String TAG = "AdblockBrowser.AddOnBridge"; | 44   private static final String TAG = "AdblockBrowser.AddOnBridge"; | 
| 38   private static final String REQUEST_NAME = "AdblockPlus:Api"; | 45   private static final String REQUEST_NAME = "AdblockPlus:Api"; | 
| 39   // Timeout for checking filter loading (in seconds) |  | 
| 40   private static final int QUERY_GET_FILTERS_LOADED_TIMEOUT = 30; |  | 
| 41   // How long to wait between retries (in milliseconds) |  | 
| 42   private static final int QUERY_GET_FILTERS_LOADED_DELAY = 500; |  | 
| 43   // Handler+HandlerThread for posting delayed re-tries without interfering with | 46   // Handler+HandlerThread for posting delayed re-tries without interfering with | 
| 44   // other threads (e.g. the UI or Gecko thread) | 47   // other threads (e.g. the UI or Gecko thread) | 
| 45   private static final HandlerThread PRIVATE_HANDLER_THREAD; | 48   private static final HandlerThread PRIVATE_HANDLER_THREAD; | 
| 46   private static final Handler PRIVATE_HANDLER; | 49   private static final Handler PRIVATE_HANDLER; | 
| 47   // Global handler, for e.g. UI tasks | 50   // Global handler, for e.g. UI tasks | 
| 48   private static final HandlerThread GLOBAL_HANDLER_THREAD; | 51   private static final HandlerThread GLOBAL_HANDLER_THREAD; | 
| 49   private static final Handler GLOBAL_HANDLER; | 52   private static final Handler GLOBAL_HANDLER; | 
|  | 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 uncompleted requests
      on SharedPrefs, | 
|  | 55   // so we can resend them to the extension once the app restarts | 
|  | 56   // See https://issues.adblockplus.org/ticket/2853 | 
|  | 57   private static final AddOnEventListener ADD_ON_EVENT_LISTENER = new AddOnEvent
     Listener(); | 
|  | 58   private static final String ON_FILTERS_LOAD_EVENT = "Abb:OnFiltersLoad"; | 
|  | 59   private static final String ON_FILTERS_SAVE_EVENT = "Abb:OnFiltersSave"; | 
|  | 60   private static final List<AddOnRequest> PENDING_REQUESTS = new ArrayList<>(); | 
|  | 61   private static final String UNCOMPLETED_REQUESTS_PREFS_KEY = "UNCOMPLETED_REQU
     ESTS_PREFS_KEY"; | 
|  | 62 | 
|  | 63   private static SharedPreferences sharedPrefs; | 
|  | 64   private static boolean filtersLoaded; | 
| 50 | 65 | 
| 51   static | 66   static | 
| 52   { | 67   { | 
| 53     PRIVATE_HANDLER_THREAD = new HandlerThread("abp-private-handler"); | 68     PRIVATE_HANDLER_THREAD = new HandlerThread("abp-private-handler"); | 
| 54     PRIVATE_HANDLER_THREAD.setDaemon(true); | 69     PRIVATE_HANDLER_THREAD.setDaemon(true); | 
| 55     PRIVATE_HANDLER_THREAD.start(); | 70     PRIVATE_HANDLER_THREAD.start(); | 
| 56     PRIVATE_HANDLER = new Handler(PRIVATE_HANDLER_THREAD.getLooper()); | 71     PRIVATE_HANDLER = new Handler(PRIVATE_HANDLER_THREAD.getLooper()); | 
| 57 | 72 | 
| 58     GLOBAL_HANDLER_THREAD = new HandlerThread("abp-global-handler"); | 73     GLOBAL_HANDLER_THREAD = new HandlerThread("abp-global-handler"); | 
| 59     GLOBAL_HANDLER_THREAD.setDaemon(true); | 74     GLOBAL_HANDLER_THREAD.setDaemon(true); | 
| 60     GLOBAL_HANDLER_THREAD.start(); | 75     GLOBAL_HANDLER_THREAD.start(); | 
| 61     GLOBAL_HANDLER = new Handler(GLOBAL_HANDLER_THREAD.getLooper()); | 76     GLOBAL_HANDLER = new Handler(GLOBAL_HANDLER_THREAD.getLooper()); | 
| 62   } | 77   } | 
| 63 | 78 | 
|  | 79   public static void init(Context context) | 
|  | 80   { | 
|  | 81     sharedPrefs = context.getSharedPreferences(AddOnBridge.class.getName(), Cont
     ext.MODE_PRIVATE); | 
|  | 82     EventDispatcher.getInstance().registerGeckoThreadListener(ADD_ON_EVENT_LISTE
     NER, ON_FILTERS_LOAD_EVENT, ON_FILTERS_SAVE_EVENT); | 
|  | 83     loadUncompletedRequests(); | 
|  | 84   } | 
|  | 85 | 
| 64   public static void postToHandler(Runnable runnable) | 86   public static void postToHandler(Runnable runnable) | 
| 65   { | 87   { | 
| 66     GLOBAL_HANDLER.post(runnable); | 88     GLOBAL_HANDLER.post(runnable); | 
| 67   } | 89   } | 
| 68 | 90 | 
| 69   public static void postToHandlerDelayed(Runnable runnable, long delayMillis) | 91   public static void postToHandlerDelayed(Runnable runnable, long delayMillis) | 
| 70   { | 92   { | 
| 71     GLOBAL_HANDLER.postDelayed(runnable, delayMillis); | 93     GLOBAL_HANDLER.postDelayed(runnable, delayMillis); | 
| 72   } | 94   } | 
| 73 | 95 | 
|  | 96   private static void loadUncompletedRequests() | 
|  | 97   { | 
|  | 98     PRIVATE_HANDLER.post(new Runnable() | 
|  | 99     { | 
|  | 100       @Override | 
|  | 101       public void run() | 
|  | 102       { | 
|  | 103         final String jsonString = sharedPrefs.getString(UNCOMPLETED_REQUESTS_PRE
     FS_KEY, null); | 
|  | 104         PENDING_REQUESTS.addAll(0, jsonStringToRequestList(jsonString)); | 
|  | 105       } | 
|  | 106     }); | 
|  | 107   } | 
|  | 108 | 
|  | 109   private static void sendOrEnqueueRequest(final AddOnRequest request) | 
|  | 110   { | 
|  | 111     PRIVATE_HANDLER.post(new Runnable() | 
|  | 112     { | 
|  | 113       @Override | 
|  | 114       public void run() | 
|  | 115       { | 
|  | 116         if (!filtersLoaded) | 
|  | 117         { | 
|  | 118           PENDING_REQUESTS.add(request); | 
|  | 119         } | 
|  | 120         else | 
|  | 121         { | 
|  | 122           GeckoAppShell.sendRequestToGecko(request); | 
|  | 123         } | 
|  | 124       } | 
|  | 125     }); | 
|  | 126   } | 
|  | 127 | 
|  | 128   private static void sendPendingRequests() | 
|  | 129   { | 
|  | 130     PRIVATE_HANDLER.post(new Runnable() | 
|  | 131     { | 
|  | 132       @Override | 
|  | 133       public void run() | 
|  | 134       { | 
|  | 135         for (final AddOnRequest request : PENDING_REQUESTS) | 
|  | 136         { | 
|  | 137           GeckoAppShell.sendRequestToGecko(request); | 
|  | 138         } | 
|  | 139         PENDING_REQUESTS.clear(); | 
|  | 140       } | 
|  | 141     }); | 
|  | 142   } | 
|  | 143 | 
|  | 144   private static void clearUncompletedRequests() | 
|  | 145   { | 
|  | 146     PRIVATE_HANDLER.post(new Runnable() | 
|  | 147     { | 
|  | 148       @Override | 
|  | 149       public void run() | 
|  | 150       { | 
|  | 151         storeStringPref(UNCOMPLETED_REQUESTS_PREFS_KEY, null); | 
|  | 152       } | 
|  | 153     }); | 
|  | 154   } | 
|  | 155 | 
|  | 156   private static void storeUncompletedRequest(final AddOnRequest request) | 
|  | 157   { | 
|  | 158     PRIVATE_HANDLER.post(new Runnable() | 
|  | 159     { | 
|  | 160       @Override | 
|  | 161       public void run() | 
|  | 162       { | 
|  | 163         final String jsonString = sharedPrefs.getString(UNCOMPLETED_REQUESTS_PRE
     FS_KEY, null); | 
|  | 164         try | 
|  | 165         { | 
|  | 166           final JSONArray jsonArray = jsonString != null ? new JSONArray(jsonStr
     ing) : new JSONArray(); | 
|  | 167           jsonArray.put(request.value); | 
|  | 168           storeStringPref(UNCOMPLETED_REQUESTS_PREFS_KEY, jsonArray.toString()); | 
|  | 169         } | 
|  | 170         catch (JSONException e) | 
|  | 171         { | 
|  | 172           Log.e(TAG, "Failed to store uncompleted request with error: " + e.getM
     essage(), 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) | 
|  | 182     { | 
|  | 183       return requestList; | 
|  | 184     } | 
|  | 185     try | 
|  | 186     { | 
|  | 187       final JSONArray jsonArray = new JSONArray(jsonString); | 
|  | 188       for (int i = 0; i < jsonArray.length(); i++) | 
|  | 189       { | 
|  | 190         final AddOnRequest request = new AddOnRequest(jsonArray.getJSONObject(i)
     , null); | 
|  | 191         requestList.add(request); | 
|  | 192       } | 
|  | 193     } | 
|  | 194     catch (JSONException e) | 
|  | 195     { | 
|  | 196       Log.e(TAG, "Failed to parse json to request list with error: " + e.getMess
     age(), e); | 
|  | 197     } | 
|  | 198     return requestList; | 
|  | 199   } | 
|  | 200 | 
|  | 201   private static void storeStringPref(String key, String value) | 
|  | 202   { | 
|  | 203     final SharedPreferences.Editor editor = sharedPrefs.edit(); | 
|  | 204     editor.putString(key, value); | 
|  | 205     editor.commit(); | 
|  | 206   } | 
|  | 207 | 
| 74   public static boolean getBooleanFromJsObject(final NativeJSObject obj, final S
     tring name, | 208   public static boolean getBooleanFromJsObject(final NativeJSObject obj, final S
     tring name, | 
| 75       final boolean defaultValue) | 209       final boolean defaultValue) | 
| 76   { | 210   { | 
| 77     try | 211     try | 
| 78     { | 212     { | 
| 79       return obj.getBoolean(name); | 213       return obj.getBoolean(name); | 
| 80     } | 214     } | 
| 81     catch (final Exception e) | 215     catch (final Exception e) | 
| 82     { | 216     { | 
| 83       return defaultValue; | 217       return defaultValue; | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 132     if (Character.isUpperCase(str.charAt(0))) | 266     if (Character.isUpperCase(str.charAt(0))) | 
| 133     { | 267     { | 
| 134       return str; | 268       return str; | 
| 135     } | 269     } | 
| 136     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); | 
| 137   } | 271   } | 
| 138 | 272 | 
| 139   public static void queryValue(final AdblockPlusApiCallback callback, final Str
     ing name) | 273   public static void queryValue(final AdblockPlusApiCallback callback, final Str
     ing name) | 
| 140   { | 274   { | 
| 141     Log.d(TAG, "queryValue for " + name); | 275     Log.d(TAG, "queryValue for " + name); | 
| 142     GeckoAppShell.sendRequestToGecko( | 276     final AddOnRequest request = | 
| 143         new ChainedRequest( | 277         new AddOnRequest(createRequestData("get" + makeFirstCharacterUppercase(n
     ame)), callback); | 
| 144             createRequestData("get" + makeFirstCharacterUppercase(name)), | 278     sendOrEnqueueRequest(request); | 
| 145             callback)); |  | 
| 146   } | 279   } | 
| 147 | 280 | 
| 148   public static void setBoolean(final AdblockPlusApiCallback callback, final Str
     ing name, | 281   public static void setBoolean(final AdblockPlusApiCallback callback, final Str
     ing name, | 
| 149       final boolean enable) | 282       final boolean enable) | 
| 150   { | 283   { | 
| 151     Log.d(TAG, "setBoolean " + enable + " for " + name); | 284     Log.d(TAG, "setBoolean " + enable + " for " + name); | 
| 152     GeckoAppShell.sendRequestToGecko( | 285     final AddOnRequest request = | 
| 153         new ChainedRequest( | 286         new AddOnRequest(createRequestData("set" + makeFirstCharacterUppercase(n
     ame), enable), callback); | 
| 154             createRequestData("set" + makeFirstCharacterUppercase(name), enable)
     , | 287     sendOrEnqueueRequest(request); | 
| 155             callback)); | 288     storeUncompletedRequest(request); | 
| 156   } | 289   } | 
| 157 | 290 | 
| 158   private static void callFunction(final AdblockPlusApiCallback callback, final 
     String name, | 291   private static void callFunction(final AdblockPlusApiCallback callback, final 
     String name, | 
| 159       final Map<String, Object> parameters) | 292       final Map<String, Object> parameters) | 
| 160   { | 293   { | 
|  | 294     // By default, requests are not stored on the uncompleted request prefs. Thi
     s should apply for | 
|  | 295     // requests that doesn't result in save operations performed by the extensio
     n | 
|  | 296     callFunction(callback, name, parameters, false); | 
|  | 297   } | 
|  | 298 | 
|  | 299   private static void callFunction(final AdblockPlusApiCallback callback, final 
     String name, | 
|  | 300       final Map<String, Object> parameters, boolean resendIfAborted) | 
|  | 301   { | 
| 161     final JSONObject requestData = createRequestData(name); | 302     final JSONObject requestData = createRequestData(name); | 
| 162     try | 303     try | 
| 163     { | 304     { | 
| 164       for (Map.Entry<String, Object> entry : parameters.entrySet()) | 305       for (Map.Entry<String, Object> entry : parameters.entrySet()) | 
|  | 306       { | 
| 165         requestData.put(entry.getKey(), entry.getValue()); | 307         requestData.put(entry.getKey(), entry.getValue()); | 
|  | 308       } | 
| 166     } | 309     } | 
| 167     catch (JSONException e) | 310     catch (JSONException e) | 
| 168     { | 311     { | 
| 169       // we're only adding sane objects | 312       // we're only adding sane objects | 
| 170       Log.e(TAG, "Creating request data failed with: " + e.getMessage(), e); | 313       Log.e(TAG, "Creating request data failed with: " + e.getMessage(), e); | 
| 171     } | 314     } | 
| 172     GeckoAppShell.sendRequestToGecko(new ChainedRequest(requestData, callback)); | 315     final AddOnRequest request = new AddOnRequest(requestData, callback); | 
|  | 316     sendOrEnqueueRequest(request); | 
|  | 317     if (resendIfAborted) | 
|  | 318     { | 
|  | 319       storeUncompletedRequest(request); | 
|  | 320     } | 
| 173   } | 321   } | 
| 174 | 322 | 
| 175   public static void querySubscriptionListStatus(final AdblockPlusApiCallback ca
     llback, | 323   public static void querySubscriptionListStatus(final AdblockPlusApiCallback ca
     llback, | 
| 176       final String url) | 324       final String url) | 
| 177   { | 325   { | 
| 178     Log.d(TAG, "querySubscriptionListStatus for " + url); | 326     Log.d(TAG, "querySubscriptionListStatus for " + url); | 
| 179     final Map<String, Object> parameters = new HashMap<String, Object>(); | 327     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 180     parameters.put("url", url); | 328     parameters.put("url", url); | 
| 181     callFunction(callback, "isSubscriptionListed", parameters); | 329     callFunction(callback, "isSubscriptionListed", parameters); | 
| 182   } | 330   } | 
| 183 | 331 | 
| 184   public static void addSubscription(final AdblockPlusApiCallback callback, | 332   public static void addSubscription(final AdblockPlusApiCallback callback, | 
| 185       final String url, final String title) | 333       final String url, final String title) | 
| 186   { | 334   { | 
| 187     Log.d(TAG, "addSubscription for " + url + " (" + title + ")"); | 335     Log.d(TAG, "addSubscription for " + url + " (" + title + ")"); | 
| 188     final Map<String, Object> parameters = new HashMap<String, Object>(); | 336     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 189     parameters.put("url", url); | 337     parameters.put("url", url); | 
| 190     if (title != null) | 338     if (title != null) | 
| 191     { | 339     { | 
| 192       parameters.put("title", title); | 340       parameters.put("title", title); | 
| 193     } | 341     } | 
| 194     callFunction(callback, "addSubscription", parameters); | 342     callFunction(callback, "addSubscription", parameters, true); | 
| 195   } | 343   } | 
| 196 | 344 | 
| 197   public static void queryActiveSubscriptions(final AdblockPlusApiCallback callb
     ack) | 345   public static void queryActiveSubscriptions(final AdblockPlusApiCallback callb
     ack) | 
| 198   { | 346   { | 
| 199     Log.d(TAG, "queryActiveSubscriptions"); | 347     Log.d(TAG, "queryActiveSubscriptions"); | 
| 200     final Map<String, Object> parameters = new HashMap<String, Object>(); | 348     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 201     callFunction(callback, "getActiveSubscriptions", parameters); | 349     callFunction(callback, "getActiveSubscriptions", parameters); | 
| 202   } | 350   } | 
| 203 | 351 | 
| 204   public static void removeSubscription(final AdblockPlusApiCallback callback, | 352   public static void removeSubscription(final AdblockPlusApiCallback callback, | 
| 205       final String url) | 353       final String url) | 
| 206   { | 354   { | 
| 207     Log.d(TAG, "removeSubscription for " + url); | 355     Log.d(TAG, "removeSubscription for " + url); | 
| 208     final Map<String, Object> parameters = new HashMap<String, Object>(); | 356     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 209     parameters.put("url", url); | 357     parameters.put("url", url); | 
| 210     callFunction(callback, "removeSubscription", parameters); | 358     callFunction(callback, "removeSubscription", parameters, true); | 
| 211   } | 359   } | 
| 212 | 360 | 
| 213   public static void queryIsLocal(final AdblockPlusApiCallback callback, | 361   public static void queryIsLocal(final AdblockPlusApiCallback callback, | 
| 214       final String url) | 362       final String url) | 
| 215   { | 363   { | 
| 216     Log.d(TAG, "queryIsLocal for " + url); | 364     Log.d(TAG, "queryIsLocal for " + url); | 
| 217     final Map<String, Object> parameters = new HashMap<String, Object>(); | 365     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 218     parameters.put("url", url); | 366     parameters.put("url", url); | 
| 219     callFunction(callback, "isLocal", parameters); | 367     callFunction(callback, "isLocal", parameters); | 
| 220   } | 368   } | 
| 221 | 369 | 
| 222   public static void queryIsPageWhitelisted(final AdblockPlusApiCallback callbac
     k, | 370   public static void queryIsPageWhitelisted(final AdblockPlusApiCallback callbac
     k, | 
| 223       final String url) | 371       final String url) | 
| 224   { | 372   { | 
| 225     Log.d(TAG, "queryIsPageWhitelisted for " + url); | 373     Log.d(TAG, "queryIsPageWhitelisted for " + url); | 
| 226     final Map<String, Object> parameters = new HashMap<String, Object>(); | 374     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 227     parameters.put("url", url); | 375     parameters.put("url", url); | 
| 228     callFunction(callback, "isPageWhitelisted", parameters); | 376     callFunction(callback, "isPageWhitelisted", parameters); | 
| 229   } | 377   } | 
| 230 | 378 | 
| 231   public static void whitelistSite(final AdblockPlusApiCallback callback, final 
     String url, | 379   public static void whitelistSite(final AdblockPlusApiCallback callback, final 
     String url, | 
| 232       final boolean whitelisted) | 380       final boolean whitelisted) | 
| 233   { | 381   { | 
| 234     Log.d(TAG, "whitelistSite for " + url); | 382     Log.d(TAG, "whitelistSite for " + url); | 
| 235     final Map<String, Object> parameters = new HashMap<String, Object>(); | 383     final Map<String, Object> parameters = new HashMap<String, Object>(); | 
| 236     parameters.put("url", url); | 384     parameters.put("url", url); | 
| 237     parameters.put("whitelisted", whitelisted); | 385     parameters.put("whitelisted", whitelisted); | 
| 238     callFunction(callback, "whitelistSite", parameters); | 386     callFunction(callback, "whitelistSite", parameters, true); | 
| 239   } | 387   } | 
| 240 | 388 | 
| 241   private static class ChainedRequest extends GeckoRequest | 389   private static class AddOnRequest extends GeckoRequest | 
| 242   { | 390   { | 
| 243     private final JSONObject value; | 391     private final JSONObject value; | 
| 244     private final AdblockPlusApiCallback apiCallback; | 392     private final AdblockPlusApiCallback apiCallback; | 
| 245     private final boolean checkForFiltersLoaded; |  | 
| 246     private final long creationTime; |  | 
| 247 | 393 | 
| 248     public ChainedRequest(final JSONObject value, final AdblockPlusApiCallback c
     allback, | 394     AddOnRequest(final JSONObject value, final AdblockPlusApiCallback callback) | 
| 249         final boolean checkForFiltersLoaded, final long creationTime) |  | 
| 250     { | 395     { | 
| 251       super(AddOnBridge.REQUEST_NAME, | 396       super(AddOnBridge.REQUEST_NAME, value); | 
| 252           checkForFiltersLoaded ? createRequestData("getFiltersLoaded") : value)
     ; |  | 
| 253       this.value = value; | 397       this.value = value; | 
| 254       this.apiCallback = callback; | 398       this.apiCallback = callback; | 
| 255       this.checkForFiltersLoaded = checkForFiltersLoaded; |  | 
| 256       this.creationTime = creationTime; |  | 
| 257     } |  | 
| 258 |  | 
| 259     public ChainedRequest(final JSONObject value, final AdblockPlusApiCallback c
     allback) |  | 
| 260     { |  | 
| 261       this(value, callback, true, System.currentTimeMillis()); |  | 
| 262     } |  | 
| 263 |  | 
| 264     public ChainedRequest cloneForRetry() |  | 
| 265     { |  | 
| 266       return new ChainedRequest(this.value, this.apiCallback, true, this.creatio
     nTime); |  | 
| 267     } |  | 
| 268 |  | 
| 269     public ChainedRequest cloneForRequest() |  | 
| 270     { |  | 
| 271       return new ChainedRequest(this.value, this.apiCallback, false, this.creati
     onTime); |  | 
| 272     } | 399     } | 
| 273 | 400 | 
| 274     private void invokeSuccessCallback(final NativeJSObject jsObject) | 401     private void invokeSuccessCallback(final NativeJSObject jsObject) | 
| 275     { | 402     { | 
| 276       try | 403       try | 
| 277       { | 404       { | 
| 278         if (this.apiCallback != null) | 405         if (this.apiCallback != null) | 
| 279         { | 406         { | 
| 280           this.apiCallback.onApiRequestSucceeded(jsObject); | 407           this.apiCallback.onApiRequestSucceeded(jsObject); | 
| 281         } | 408         } | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 292       { | 419       { | 
| 293         this.apiCallback.onApiRequestFailed(msg); | 420         this.apiCallback.onApiRequestFailed(msg); | 
| 294       } | 421       } | 
| 295     } | 422     } | 
| 296 | 423 | 
| 297     private void invokeFailureCallback(final NativeJSObject jsObject) | 424     private void invokeFailureCallback(final NativeJSObject jsObject) | 
| 298     { | 425     { | 
| 299       invokeFailureCallback(getStringFromJsObject(jsObject, "error", "unknown er
     ror")); | 426       invokeFailureCallback(getStringFromJsObject(jsObject, "error", "unknown er
     ror")); | 
| 300     } | 427     } | 
| 301 | 428 | 
| 302     private void attemptRetry() |  | 
| 303     { |  | 
| 304       if (System.currentTimeMillis() - this.creationTime > (QUERY_GET_FILTERS_LO
     ADED_TIMEOUT * 1000)) |  | 
| 305       { |  | 
| 306         this.invokeFailureCallback("getFiltersLoaded timeout"); |  | 
| 307       } |  | 
| 308       else |  | 
| 309       { |  | 
| 310         Log.d(TAG, "Retrying: " + this.value); |  | 
| 311         final ChainedRequest next = this.cloneForRetry(); |  | 
| 312         PRIVATE_HANDLER.postDelayed(new Runnable() |  | 
| 313         { |  | 
| 314           @Override |  | 
| 315           public void run() |  | 
| 316           { |  | 
| 317             GeckoAppShell.sendRequestToGecko(next); |  | 
| 318           } |  | 
| 319         }, QUERY_GET_FILTERS_LOADED_DELAY); |  | 
| 320       } |  | 
| 321     } |  | 
| 322 |  | 
| 323     @Override | 429     @Override | 
| 324     public void onError(final NativeJSObject error) | 430     public void onError(final NativeJSObject error) | 
| 325     { | 431     { | 
| 326       if (this.checkForFiltersLoaded) | 432       this.invokeFailureCallback( | 
| 327       { | 433           "GeckoRequest error: " + error.optString("message", "<no message>") + 
     "\n" + | 
| 328         this.attemptRetry(); | 434               error.optString("stack", "<no stack>")); | 
| 329       } |  | 
| 330       else |  | 
| 331       { |  | 
| 332         this.invokeFailureCallback( |  | 
| 333             "GeckoRequest error: " + error.optString("message", "<no message>") 
     + "\n" + |  | 
| 334             error.optString("stack", "<no stack>")); |  | 
| 335       } |  | 
| 336     } | 435     } | 
| 337 | 436 | 
| 338     @Override | 437     @Override | 
| 339     public void onResponse(final NativeJSObject jsObject) | 438     public void onResponse(final NativeJSObject jsObject) | 
| 340     { | 439     { | 
| 341       if (this.checkForFiltersLoaded) | 440       if (getBooleanFromJsObject(jsObject, "success", false)) | 
| 342       { | 441       { | 
| 343         if (getBooleanFromJsObject(jsObject, "success", false) | 442         this.invokeSuccessCallback(jsObject); | 
| 344             && getBooleanFromJsObject(jsObject, "value", false)) |  | 
| 345         { |  | 
| 346           GeckoAppShell.sendRequestToGecko(this.cloneForRequest()); |  | 
| 347         } |  | 
| 348         else |  | 
| 349         { |  | 
| 350           this.attemptRetry(); |  | 
| 351         } |  | 
| 352       } | 443       } | 
| 353       else | 444       else | 
| 354       { | 445       { | 
| 355         if (getBooleanFromJsObject(jsObject, "success", false)) | 446         this.invokeFailureCallback(jsObject); | 
| 356         { | 447       } | 
| 357           this.invokeSuccessCallback(jsObject); | 448     } | 
| 358         } | 449   } | 
| 359         else | 450 | 
| 360         { | 451   private static class AddOnEventListener implements GeckoEventListener | 
| 361           this.invokeFailureCallback(jsObject); | 452   { | 
| 362         } | 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         // uncompleted requests | 
|  | 466         // See https://issues.adblockplus.org/ticket/2853 | 
|  | 467         clearUncompletedRequests(); | 
| 363       } | 468       } | 
| 364     } | 469     } | 
| 365   } | 470   } | 
| 366 } | 471 } | 
| OLD | NEW | 
|---|