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