| Index: src/org/adblockplus/android/AdblockPlus.java |
| =================================================================== |
| --- a/src/org/adblockplus/android/AdblockPlus.java |
| +++ b/src/org/adblockplus/android/AdblockPlus.java |
| @@ -19,36 +19,15 @@ |
| import java.io.BufferedReader; |
| import java.io.File; |
| -import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| -import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| -import java.net.HttpURLConnection; |
| -import java.net.URL; |
| -import java.util.ArrayList; |
| import java.util.Calendar; |
| -import java.util.LinkedList; |
| -import java.util.List; |
| -import java.util.Locale; |
| -import java.util.Map; |
| import java.util.TimeZone; |
| -import java.util.concurrent.Callable; |
| -import java.util.concurrent.ExecutionException; |
| -import java.util.concurrent.Future; |
| -import java.util.concurrent.FutureTask; |
| - |
| -import javax.xml.parsers.ParserConfigurationException; |
| -import javax.xml.parsers.SAXParser; |
| -import javax.xml.parsers.SAXParserFactory; |
| +import java.util.regex.Pattern; |
| import org.adblockplus.android.updater.AlarmReceiver; |
| -import org.apache.commons.lang.StringEscapeUtils; |
| -import org.apache.commons.lang.StringUtils; |
| -import org.json.JSONException; |
| -import org.json.JSONObject; |
| -import org.xml.sax.SAXException; |
| import android.app.ActivityManager; |
| import android.app.ActivityManager.RunningServiceInfo; |
| @@ -57,30 +36,24 @@ |
| import android.app.PendingIntent; |
| import android.content.Context; |
| import android.content.Intent; |
| -import android.content.SharedPreferences; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| -import android.content.res.AssetManager; |
| import android.net.ConnectivityManager; |
| import android.net.NetworkInfo; |
| import android.net.Uri; |
| -import android.os.AsyncTask; |
| import android.os.Build; |
| -import android.os.Bundle; |
| -import android.os.Handler; |
| -import android.os.Message; |
| -import android.os.SystemClock; |
| -import android.preference.PreferenceManager; |
| import android.provider.Settings; |
| import android.util.Log; |
| -import android.widget.Toast; |
| public class AdblockPlus extends Application |
| { |
| private final static String TAG = "Application"; |
| - private final static int MSG_TOAST = 1; |
| + private final static Pattern RE_JS = Pattern.compile(".*\\.js$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_CSS = Pattern.compile(".*\\.css$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_IMAGE = Pattern.compile(".*\\.(?:gif|png|jpe?g|bmp|ico)$", Pattern.CASE_INSENSITIVE); |
| + private final static Pattern RE_FONT = Pattern.compile(".*\\.(?:ttf|woff)$", Pattern.CASE_INSENSITIVE); |
|
Wladimir Palant
2013/09/12 11:31:14
Wouldn't it make sense to drop .* at the beginning
|
| /** |
| * Broadcasted when filtering is enabled or disabled. |
| @@ -95,20 +68,14 @@ |
| */ |
| public final static String BROADCAST_FILTER_MATCHES = "org.adblockplus.android.filter.matches"; |
| - private List<Subscription> subscriptions; |
| - |
| - private JSThread js; |
| - |
| - /** |
| - * Indicates interactive mode (used to listen for subscription status |
| - * changes). |
| - */ |
| - private boolean interactive = false; |
| + private Subscription[] subscriptions; |
|
Wladimir Palant
2013/09/12 11:31:14
Add a comment explaining that this is the cached l
|
| /** |
| * Indicates whether filtering is enabled or not. |
| */ |
| private boolean filteringEnabled = false; |
| + |
| + private ABPEngine abpEngine; |
| private static AdblockPlus instance; |
| @@ -244,184 +211,65 @@ |
| return res == PackageManager.PERMISSION_GRANTED; |
| } |
| + public boolean isFirstRun() |
| + { |
| + return abpEngine.isFirstRun(); |
| + } |
| + |
| /** |
| * Returns list of known subscriptions. |
| */ |
| - public List<Subscription> getSubscriptions() |
| + public Subscription[] getRecommendedSubscriptions() |
| { |
| if (subscriptions == null) |
| - { |
| - subscriptions = new ArrayList<Subscription>(); |
| - |
| - SAXParserFactory factory = SAXParserFactory.newInstance(); |
| - SAXParser parser; |
| - try |
| - { |
| - parser = factory.newSAXParser(); |
| - parser.parse(getAssets().open("subscriptions.xml"), new SubscriptionParser(subscriptions)); |
| - } |
| - catch (ParserConfigurationException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - catch (SAXException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - catch (IOException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - } |
| + subscriptions = abpEngine.getRecommendedSubscriptions(); |
| return subscriptions; |
| } |
| /** |
| - * Returns subscription information. |
| - * |
| - * @param url |
| - * subscription url |
| + * Returns list of enabled subscriptions. |
| */ |
| - public Subscription getSubscription(String url) |
| + public Subscription[] getListedSubscriptions() |
| { |
| - List<Subscription> subscriptions = getSubscriptions(); |
| - |
| - for (Subscription subscription : subscriptions) |
| - { |
| - if (subscription.url.equals(url)) |
| - return subscription; |
| - } |
| - return null; |
| + return abpEngine.getListedSubscriptions(); |
| } |
| /** |
| * Adds provided subscription and removes previous subscriptions if any. |
| * |
| - * @param subscription |
| - * Subscription to add |
| + * @param url |
| + * URL of subscription to add |
| */ |
| - public void setSubscription(Subscription subscription) |
| + public void setSubscription(String url) |
| { |
| - if (subscription != null) |
| + Subscription[] subscriptions = abpEngine.getListedSubscriptions(); |
| + for (Subscription subscription : subscriptions) |
| { |
| - final JSONObject jsonSub = new JSONObject(); |
| - try |
| - { |
| - jsonSub.put("url", subscription.url); |
| - jsonSub.put("title", subscription.title); |
| - jsonSub.put("homepage", subscription.homepage); |
| - js.execute(new Runnable() |
| - { |
| - @Override |
| - public void run() |
| - { |
| - js.evaluate("clearSubscriptions()"); |
| - js.evaluate("addSubscription(\"" + StringEscapeUtils.escapeJavaScript(jsonSub.toString()) + "\")"); |
| - } |
| - }); |
| - } |
| - catch (JSONException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| + abpEngine.removeSubscription(subscription.url); |
| } |
| + abpEngine.addSubscription(url); |
| } |
| /** |
| * Forces subscriptions refresh. |
| */ |
| - public void refreshSubscription() |
| + public void refreshSubscriptions() |
| { |
| - js.execute(new Runnable() |
| + Subscription[] subscriptions = abpEngine.getListedSubscriptions(); |
| + for (Subscription subscription : subscriptions) |
| { |
| - @Override |
| - public void run() |
| - { |
| - js.evaluate("refreshSubscriptions()"); |
| - } |
| - }); |
| + abpEngine.refreshSubscription(subscription.url); |
| + } |
| } |
| - |
| + |
| /** |
| - * Selects which subscription to offer for the first time. |
| + * Enforces subscription status update. |
| * |
| - * @return offered subscription |
| + * @param url Subscription url |
| */ |
| - public Subscription offerSubscription() |
| + public void actualizeSubscriptionStatus(String url) |
| { |
| - Subscription selectedItem = null; |
| - String selectedPrefix = null; |
| - int matchCount = 0; |
| - for (Subscription subscription : getSubscriptions()) |
| - { |
| - if (selectedItem == null) |
| - selectedItem = subscription; |
| - |
| - String prefix = checkLocalePrefixMatch(subscription.prefixes); |
| - if (prefix != null) |
| - { |
| - if (selectedPrefix == null || selectedPrefix.length() < prefix.length()) |
| - { |
| - selectedItem = subscription; |
| - selectedPrefix = prefix; |
| - matchCount = 1; |
| - } |
| - else if (selectedPrefix != null && selectedPrefix.length() == prefix.length()) |
| - { |
| - matchCount++; |
| - |
| - // If multiple items have a matching prefix of the |
| - // same length select one of the items randomly, |
| - // probability should be the same for all items. |
| - // So we replace the previous match here with |
| - // probability 1/N (N being the number of matches). |
| - if (Math.random() * matchCount < 1) |
| - { |
| - selectedItem = subscription; |
| - selectedPrefix = prefix; |
| - } |
| - } |
| - } |
| - } |
| - return selectedItem; |
| - } |
| - |
| - /** |
| - * Verifies that subscriptions are loaded and returns flag of subscription |
| - * presence. |
| - * |
| - * @return true if at least one subscription is present and downloaded |
| - */ |
| - public boolean verifySubscriptions() |
| - { |
| - Future<Boolean> future = js.submit(new Callable<Boolean>() |
| - { |
| - @Override |
| - public Boolean call() throws Exception |
| - { |
| - Boolean result = (Boolean) js.evaluate("verifySubscriptions()"); |
| - return result; |
| - } |
| - }); |
| - try |
| - { |
| - return future.get().booleanValue(); |
| - } |
| - catch (InterruptedException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - catch (ExecutionException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - return false; |
| + abpEngine.actualizeSubscriptionStatus(url); |
| } |
| /** |
| @@ -429,60 +277,12 @@ |
| * |
| * @return ready to use HTML element with CSS selectors |
|
Wladimir Palant
2013/09/12 11:31:14
This comment doesn't seem to match the actual retu
|
| */ |
| - public String getSelectorsForDomain(final String domain) |
| + public String[] getSelectorsForDomain(final String domain) |
| { |
| if (!filteringEnabled) |
| return null; |
| - Future<String> future = js.submit(new Callable<String>() |
| - { |
| - @Override |
| - public String call() throws Exception |
| - { |
| - String result = (String) js.evaluate("ElemHide.getSelectorsForDomain('" + domain + "')"); |
| - return result; |
| - } |
| - }); |
| - try |
| - { |
| - return future.get(); |
| - } |
| - catch (InterruptedException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - catch (ExecutionException e) |
| - { |
| - // TODO Auto-generated catch block |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - return null; |
| - } |
| - |
| - private class MatchesCallable implements Callable<Boolean> |
| - { |
| - private String url; |
| - private String query; |
| - private String reqHost; |
| - private String refHost; |
| - private String accept; |
| - |
| - MatchesCallable(String url, String query, String reqHost, String refHost, String accept) |
| - { |
| - this.url = StringEscapeUtils.escapeJavaScript(url); |
| - this.query = StringEscapeUtils.escapeJavaScript(query); |
| - this.reqHost = reqHost != null ? StringEscapeUtils.escapeJavaScript(reqHost) : ""; |
| - this.refHost = refHost != null ? StringEscapeUtils.escapeJavaScript(refHost) : ""; |
| - this.accept = accept != null ? StringEscapeUtils.escapeJavaScript(accept) : ""; |
| - } |
| - |
| - @Override |
| - public Boolean call() throws Exception |
| - { |
| - Boolean result = (Boolean) js.evaluate("matchesAny('" + url + "', '" + query + "', '" + reqHost + "', '" + refHost + "', '" + accept + "');"); |
| - return result; |
| - } |
| + return abpEngine.getSelectorsForDomain(domain); |
| } |
| /** |
| @@ -492,25 +292,46 @@ |
| * Request URL |
| * @param query |
| * Request query string |
| - * @param reqHost |
| - * Request host |
| - * @param refHost |
| + * @param referrer |
| * Request referrer header |
| * @param accept |
| * Request accept header |
| * @return true if matched filter was found |
| * @throws Exception |
| */ |
| - public boolean matches(String url, String query, String reqHost, String refHost, String accept) throws Exception |
| + public boolean matches(String url, String query, String referrer, String accept) |
| { |
| if (!filteringEnabled) |
| return false; |
| + |
| + String contentType = null; |
| - Callable<Boolean> callable = new MatchesCallable(url, query, reqHost, refHost, accept); |
| - Future<Boolean> future = js.submit(callable); |
| - boolean matches = future.get().booleanValue(); |
| - sendBroadcast(new Intent(BROADCAST_FILTER_MATCHES).putExtra("url", url).putExtra("matches", matches)); |
| - return matches; |
| + if (accept != null) |
| + { |
| + if (accept.contains("text/css")) |
| + contentType = "STYLESHEET"; |
| + else if (accept.contains("image/*")) |
| + contentType = "IMAGE"; |
| + } |
| + |
| + if (contentType == null) |
| + { |
| + if (RE_JS.matcher(url).matches()) |
| + contentType = "SCRIPT"; |
| + else if (RE_CSS.matcher(url).matches()) |
| + contentType = "STYLESHEET"; |
| + else if (RE_IMAGE.matcher(url).matches()) |
| + contentType = "IMAGE"; |
| + else if (RE_FONT.matcher(url).matches()) |
| + contentType = "FONT"; |
| + } |
| + if (contentType == null) |
| + contentType = "OTHER"; |
| + |
| + if (!"".equals(query)) |
| + url = url + "?" + query; |
| + |
| + return abpEngine.matches(url, contentType, referrer); |
| } |
| /** |
| @@ -531,65 +352,21 @@ |
| } |
| /** |
| - * Notifies JS code that application entered interactive mode. |
| - */ |
| - public void startInteractive() |
| - { |
| - js.execute(new Runnable() |
| - { |
| - @Override |
| - public void run() |
| - { |
| - js.evaluate("startInteractive()"); |
| - } |
| - }); |
| - interactive = true; |
| - } |
| - |
| - /** |
| - * Notifies JS code that application quit interactive mode. |
| - */ |
| - public void stopInteractive() |
| - { |
| - // onStop is sometimes called without prior calling onStart |
| - // by Android system |
| - if (js == null) |
| - return; |
| - |
| - js.execute(new Runnable() |
| - { |
| - @Override |
| - public void run() |
| - { |
| - js.evaluate("stopInteractive()"); |
| - } |
| - }); |
| - interactive = false; |
| - } |
| - |
| - /** |
| - * Returns prefixes that match current user locale. |
| - */ |
| - public String checkLocalePrefixMatch(String[] prefixes) |
| - { |
| - if (prefixes == null || prefixes.length == 0) |
| - return null; |
| - |
| - String locale = Locale.getDefault().toString().toLowerCase(); |
| - |
| - for (int i = 0; i < prefixes.length; i++) |
| - if (locale.startsWith(prefixes[i].toLowerCase())) |
| - return prefixes[i]; |
| - |
| - return null; |
| - } |
| - |
| - /** |
| - * Starts JS engine. It also initiates subscription refresh if it is enabled |
| + * Starts ABP engine. It also initiates subscription refresh if it is enabled |
| * in user settings. |
| */ |
| public void startEngine() |
| { |
| + if (abpEngine == null) |
| + { |
| + File basePath = getFilesDir(); |
| +// jsEngine.put("_locale", Locale.getDefault().toString()); |
| +// jsEngine.put("_datapath", getFilesDir().getAbsolutePath()); |
| +// jsEngine.put("_separator", File.separator); |
| +// jsEngine.put("_version", getVersion()); |
|
Wladimir Palant
2013/09/12 11:31:14
I guess you intend to remove that code or replace
|
| + abpEngine = new ABPEngine(this, basePath.getAbsolutePath()); |
| + } |
| + /* |
| if (js == null) |
| { |
| Log.i(TAG, "startEngine"); |
| @@ -602,33 +379,22 @@ |
| // Refresh if user selected refresh on each start |
| if (refresh == 1 && (!wifionly || isWiFiConnected(this))) |
| { |
| - refreshSubscription(); |
| + refreshSubscriptions(); |
| } |
| } |
| + */ |
|
Wladimir Palant
2013/09/12 11:31:14
I guess you intend to remove that code?
|
| } |
| /** |
| - * Stops JS engine. |
| - * |
| - * @param implicitly |
| - * stop even in interactive mode |
| + * Stops ABP engine. |
| */ |
| - public void stopEngine(boolean implicitly) |
| + public void stopEngine() |
| { |
| - if ((implicitly || !interactive) && js != null) |
| + if (abpEngine != null) |
| { |
| + abpEngine.release(); |
| + abpEngine = null; |
| Log.i(TAG, "stopEngine"); |
| - js.stopEngine(); |
| - try |
| - { |
| - js.join(); |
| - } |
| - catch (InterruptedException e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - Log.i(TAG, "Engine stopped"); |
| - js = null; |
| } |
| } |
| @@ -712,442 +478,4 @@ |
| // Initiate update check |
| scheduleUpdater(0); |
| } |
| - |
| - /** |
| - * Handler for showing toast messages from JS code. |
| - */ |
| - private static final Handler messageHandler = new Handler() |
| - { |
| - public void handleMessage(Message msg) |
| - { |
| - if (msg.what == MSG_TOAST) |
| - { |
| - Toast.makeText(AdblockPlus.getApplication(), msg.getData().getString("message"), Toast.LENGTH_LONG).show(); |
| - } |
| - } |
| - }; |
| - |
| - /** |
| - * JS execution thread. |
| - */ |
| - private final class JSThread extends Thread |
| - { |
| - private JSEngine jsEngine; |
| - private volatile boolean run = true; |
| - private Context context; |
| - private final LinkedList<Runnable> queue = new LinkedList<Runnable>(); |
| - private long delay = -1; |
| - |
| - JSThread(Context context) |
| - { |
| - this.context = context; |
| - } |
| - |
| - // JS helper |
| - @SuppressWarnings("unused") |
| - public String readJSFile(String name) |
| - { |
| - String result = ""; |
| - AssetManager assetManager = getAssets(); |
| - try |
| - { |
| - InputStreamReader reader = new InputStreamReader(assetManager.open("js" + File.separator + name)); |
| - final char[] buffer = new char[0x10000]; |
| - StringBuilder out = new StringBuilder(); |
| - int read; |
| - do |
| - { |
| - read = reader.read(buffer, 0, buffer.length); |
| - if (read > 0) |
| - out.append(buffer, 0, read); |
| - } |
| - while (read >= 0); |
| - result = out.toString(); |
| - } |
| - catch (IOException e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - return result; |
| - } |
| - |
| - // JS helper |
| - public FileInputStream getInputStream(String path) |
| - { |
| - Log.d(TAG, path); |
| - File f = new File(path); |
| - try |
| - { |
| - return openFileInput(f.getName()); |
| - } |
| - catch (FileNotFoundException e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - return null; |
| - } |
| - |
| - // JS helper |
| - public FileOutputStream getOutputStream(String path) |
| - { |
| - Log.d(TAG, path); |
| - File f = new File(path); |
| - try |
| - { |
| - return openFileOutput(f.getName(), MODE_PRIVATE); |
| - } |
| - catch (FileNotFoundException e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - return null; |
| - } |
| - |
| - // JS helper |
| - public String getVersion() |
| - { |
| - String versionName = null; |
| - try |
| - { |
| - versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; |
| - } |
| - catch (NameNotFoundException ex) |
| - { |
| - versionName = "n/a"; |
| - } |
| - return versionName; |
| - } |
| - |
| - // JS helper |
| - @SuppressWarnings("unused") |
| - public boolean canAutoupdate() |
| - { |
| - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); |
| - final int refresh = Integer.valueOf(prefs.getString(getString(R.string.pref_refresh), Integer.toString(context.getResources().getInteger(R.integer.def_refresh)))); |
| - final boolean wifionly = prefs.getBoolean(getString(R.string.pref_wifirefresh), getResources().getBoolean(R.bool.def_wifirefresh)); |
| - return refresh == 2 && (!wifionly || isWiFiConnected(context)); |
| - } |
| - |
| - // JS helper |
| - @SuppressWarnings("unused") |
| - public void httpSend(final String method, final String url, final String[][] headers, final boolean async, final long callback) |
| - { |
| - Log.d(TAG, "httpSend('" + method + "', '" + url + "')"); |
| - messageHandler.post(new Runnable() |
| - { |
| - @Override |
| - public void run() |
| - { |
| - try |
| - { |
| - Task task = new Task(); |
| - task.callback = callback; |
| - task.connection = (HttpURLConnection) new URL(url).openConnection(); |
| - task.connection.setRequestMethod(method); |
| - for (int i = 0; i < headers.length; i++) |
| - { |
| - task.connection.setRequestProperty(headers[i][0], headers[i][1]); |
| - } |
| - DownloadTask downloadTask = new DownloadTask(context); |
| - downloadTask.execute(task); |
| - if (!async) |
| - { |
| - downloadTask.get(); |
| - } |
| - } |
| - catch (Exception e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - js.callback(callback, null); |
| - } |
| - } |
| - }); |
| - } |
| - |
| - // JS helper |
| - @SuppressWarnings("unused") |
| - public void setStatus(String text, long time) |
| - { |
| - sendBroadcast(new Intent(BROADCAST_SUBSCRIPTION_STATUS).putExtra("text", text).putExtra("time", time)); |
| - } |
| - |
| - // JS helper |
| - @SuppressWarnings("unused") |
| - public void showToast(String text) |
| - { |
| - Log.d(TAG, "Toast: " + text); |
| - Message msg = messageHandler.obtainMessage(MSG_TOAST); |
| - Bundle data = new Bundle(); |
| - data.putString("message", text); |
| - msg.setData(data); |
| - messageHandler.sendMessage(msg); |
| - } |
| - |
| - // JS helper |
| - @SuppressWarnings("unused") |
| - public void notify(long delay) |
| - { |
| - if (this.delay < 0 || delay < this.delay) |
| - { |
| - this.delay = delay; |
| - synchronized (queue) |
| - { |
| - queue.notify(); |
| - } |
| - } |
| - } |
| - |
| - public Object evaluate(String script) |
| - { |
| - return jsEngine.evaluate(script); |
| - } |
| - |
| - public void callback(long callback, Object[] params) |
| - { |
| - jsEngine.callback(callback, params); |
| - } |
| - |
| - public final void stopEngine() |
| - { |
| - run = false; |
| - synchronized (queue) |
| - { |
| - queue.notify(); |
| - } |
| - } |
| - |
| - public void execute(Runnable r) |
| - { |
| - synchronized (queue) |
| - { |
| - queue.addLast(r); |
| - queue.notify(); |
| - } |
| - } |
| - |
| - public <T> Future<T> submit(Callable<T> callable) |
| - { |
| - FutureTask<T> ftask = new FutureTask<T>(callable); |
| - execute(ftask); |
| - return ftask; |
| - } |
| - |
| - @Override |
| - public final void run() |
| - { |
| - if (Thread.currentThread().getName().startsWith("Thread-")) |
| - { |
| - Thread.currentThread().setName("javascript"); |
| - } |
| - |
| - jsEngine = new JSEngine(this); |
| - |
| - jsEngine.put("_locale", Locale.getDefault().toString()); |
| - jsEngine.put("_datapath", getFilesDir().getAbsolutePath()); |
| - jsEngine.put("_separator", File.separator); |
| - jsEngine.put("_version", getVersion()); |
| - |
| - try |
| - { |
| - jsEngine.evaluate("Android.load(\"start.js\");"); |
| - } |
| - catch (Exception e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - |
| - while (run) |
| - { |
| - try |
| - { |
| - Runnable r = null; |
| - synchronized (queue) |
| - { |
| - r = queue.poll(); |
| - } |
| - if (r != null) |
| - { |
| - r.run(); |
| - } |
| - else if (delay > 0) |
| - { |
| - long t = SystemClock.uptimeMillis(); |
| - synchronized (queue) |
| - { |
| - try |
| - { |
| - queue.wait(delay); |
| - } |
| - catch (InterruptedException e) |
| - { |
| - } |
| - } |
| - delay -= SystemClock.uptimeMillis() - t; |
| - } |
| - else if (delay <= 0) |
| - { |
| - delay = jsEngine.runCallbacks(); |
| - } |
| - else |
| - { |
| - synchronized (queue) |
| - { |
| - try |
| - { |
| - queue.wait(); |
| - } |
| - catch (InterruptedException e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - } |
| - } |
| - } |
| - catch (Exception e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - } |
| - } |
| - |
| - jsEngine.release(); |
| - } |
| - } |
| - |
| - /** |
| - * Helper class for XMLHttpRequest implementation. |
| - */ |
| - private class Task |
| - { |
| - HttpURLConnection connection; |
| - long callback; |
| - } |
| - |
| - /** |
| - * Helper class for XMLHttpRequest implementation. |
| - */ |
| - private class Result |
| - { |
| - long callback; |
| - int code; |
| - String message; |
| - String data; |
| - Map<String, List<String>> headers; |
| - } |
| - |
| - /** |
| - * Helper class for XMLHttpRequest implementation. |
| - */ |
| - private class DownloadTask extends AsyncTask<Task, Integer, Result> |
| - { |
| - public DownloadTask(Context context) |
| - { |
| - } |
| - |
| - @Override |
| - protected void onPreExecute() |
| - { |
| - } |
| - |
| - @Override |
| - protected void onPostExecute(Result result) |
| - { |
| - if (result != null) |
| - { |
| - final long callback = result.callback; |
| - final Object[] params = new Object[4]; |
| - |
| - String[][] headers = null; |
| - if (result.headers != null) |
| - { |
| - headers = new String[result.headers.size()][2]; |
| - int i = 0; |
| - for (String header : result.headers.keySet()) |
| - { |
| - headers[i][0] = header; |
| - headers[i][1] = StringUtils.join(result.headers.get(header).toArray(), "; "); |
| - i++; |
| - } |
| - } |
| - params[0] = result.code; |
| - params[1] = result.message; |
| - params[2] = headers; |
| - params[3] = result.data; |
| - |
| - // Do not run callback if engine was stopped |
| - if (js == null) |
| - return; |
| - |
| - js.execute(new Runnable() |
| - { |
| - @Override |
| - public void run() |
| - { |
| - js.callback(callback, params); |
| - } |
| - |
| - }); |
| - } |
| - } |
| - |
| - @Override |
| - protected void onCancelled() |
| - { |
| - } |
| - |
| - @Override |
| - protected Result doInBackground(Task... tasks) |
| - { |
| - Task task = tasks[0]; |
| - Result result = new Result(); |
| - result.callback = task.callback; |
| - try |
| - { |
| - HttpURLConnection connection = task.connection; |
| - connection.connect(); |
| - int lenghtOfFile = connection.getContentLength(); |
| - Log.d("D", "S: " + lenghtOfFile); |
| - |
| - result.code = connection.getResponseCode(); |
| - result.message = connection.getResponseMessage(); |
| - result.headers = connection.getHeaderFields(); |
| - |
| - // download the file |
| - String encoding = connection.getContentEncoding(); |
| - if (encoding == null) |
| - encoding = "utf-8"; |
| - BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding)); |
| - |
| - final char[] buffer = new char[0x10000]; |
| - StringBuilder out = new StringBuilder(); |
| - long total = 0; |
| - int read; |
| - do |
| - { |
| - read = in.read(buffer, 0, buffer.length); |
| - if (read > 0) |
| - { |
| - out.append(buffer, 0, read); |
| - total += read; |
| - publishProgress((int) (total * 100. / lenghtOfFile)); |
| - } |
| - } |
| - while (!isCancelled() && read >= 0); |
| - result.data = out.toString(); |
| - in.close(); |
| - } |
| - catch (Exception e) |
| - { |
| - Log.e(TAG, e.getMessage(), e); |
| - result.data = ""; |
| - result.code = HttpURLConnection.HTTP_INTERNAL_ERROR; |
| - result.message = e.toString(); |
| - } |
| - return result; |
| - } |
| - |
| - protected void onProgressUpdate(Integer... progress) |
| - { |
| - Log.d("HTTP", "Progress: " + progress[0].intValue()); |
| - } |
| - } |
| } |