From b5ed0266e8769c2d11bd0c8534637df5f09acff7 Mon Sep 17 00:00:00 2001 From: Xiaowei Zhao Date: Wed, 20 Aug 2014 10:45:03 +0800 Subject: [PATCH 001/167] Get rid of null check of responseHandler, also add proper synchronization --- .../com/loopj/android/http/ArgsUtils.java | 35 ++++++++++++++++ .../loopj/android/http/AsyncHttpRequest.java | 41 +++++++++---------- 2 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 library/src/main/java/com/loopj/android/http/ArgsUtils.java diff --git a/library/src/main/java/com/loopj/android/http/ArgsUtils.java b/library/src/main/java/com/loopj/android/http/ArgsUtils.java new file mode 100644 index 000000000..990a0dcb5 --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/ArgsUtils.java @@ -0,0 +1,35 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.loopj.android.http; + +/** + * Internal class, used to check non-private method's args, make sure method contract is met. + */ +class ArgsUtils { + + private ArgsUtils() { + } + + public static T notNull(final T argument, final String name) { + if (argument == null) { + throw new IllegalArgumentException(name + " should not be null!"); + } + return argument; + } +} diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index b7756d8ff..df215f382 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -33,7 +33,7 @@ /** * Internal class, representing the HttpRequest, done in asynchronous manner */ -public class AsyncHttpRequest implements Runnable { +class AsyncHttpRequest implements Runnable { private final AbstractHttpClient client; private final HttpContext context; private final HttpUriRequest request; @@ -45,10 +45,10 @@ public class AsyncHttpRequest implements Runnable { private boolean isRequestPreProcessed; public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) { - this.client = client; - this.context = context; - this.request = request; - this.responseHandler = responseHandler; + this.client = ArgsUtils.notNull(client, "client"); + this.context = ArgsUtils.notNull(context, "context"); + this.request = ArgsUtils.notNull(request, "request"); + this.responseHandler = ArgsUtils.notNull(responseHandler, "responseHandler"); } /** @@ -97,9 +97,7 @@ public void run() { return; } - if (responseHandler != null) { - responseHandler.sendStartMessage(); - } + responseHandler.sendStartMessage(); if (isCancelled()) { return; @@ -108,10 +106,10 @@ public void run() { try { makeRequestWithRetries(); } catch (IOException e) { - if (!isCancelled() && responseHandler != null) { + if (!isCancelled()) { responseHandler.sendFailureMessage(0, null, null, e); } else { - Log.e("AsyncHttpRequest", "makeRequestWithRetries returned error, but handler is null", e); + Log.e("AsyncHttpRequest", "makeRequestWithRetries returned error", e); } } @@ -119,9 +117,7 @@ public void run() { return; } - if (responseHandler != null) { - responseHandler.sendFinishMessage(); - } + responseHandler.sendFinishMessage(); if (isCancelled()) { return; @@ -130,7 +126,7 @@ public void run() { // Carry out post-processing for this request. onPostProcessRequest(this); - isFinished = true; + setFinished(true); } private void makeRequest() throws IOException { @@ -146,7 +142,7 @@ private void makeRequest() throws IOException { HttpResponse response = client.execute(request, context); - if (isCancelled() || responseHandler == null) { + if (isCancelled()) { return; } @@ -197,7 +193,7 @@ private void makeRequestWithRetries() throws IOException { cause = e; retry = retryHandler.retryRequest(cause, ++executionCount, context); } - if (retry && (responseHandler != null)) { + if (retry) { responseHandler.sendRetryMessage(executionCount); } } @@ -211,7 +207,7 @@ private void makeRequestWithRetries() throws IOException { throw (cause); } - public boolean isCancelled() { + public synchronized boolean isCancelled() { if (isCancelled) { sendCancelNotification(); } @@ -221,16 +217,19 @@ public boolean isCancelled() { private synchronized void sendCancelNotification() { if (!isFinished && isCancelled && !cancelIsNotified) { cancelIsNotified = true; - if (responseHandler != null) - responseHandler.sendCancelMessage(); + responseHandler.sendCancelMessage(); } } - public boolean isDone() { + private synchronized void setFinished(boolean finished) { + isFinished = finished; + } + + public synchronized boolean isDone() { return isCancelled() || isFinished; } - public boolean cancel(boolean mayInterruptIfRunning) { + public synchronized boolean cancel(boolean mayInterruptIfRunning) { isCancelled = true; request.abort(); return isCancelled(); From 3052d8467f002307729d4b5dc5e298a1a1c555be Mon Sep 17 00:00:00 2001 From: Xiaowei Zhao Date: Wed, 20 Aug 2014 13:48:13 +0800 Subject: [PATCH 002/167] revert it, since sample project use it --- .../src/main/java/com/loopj/android/http/AsyncHttpRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index df215f382..b2548cfb9 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -33,7 +33,7 @@ /** * Internal class, representing the HttpRequest, done in asynchronous manner */ -class AsyncHttpRequest implements Runnable { +public class AsyncHttpRequest implements Runnable { private final AbstractHttpClient client; private final HttpContext context; private final HttpUriRequest request; From 88106c430535d2caaf94bb92cdb439c69427da6b Mon Sep 17 00:00:00 2001 From: Xiaowei Zhao Date: Wed, 20 Aug 2014 22:31:18 +0800 Subject: [PATCH 003/167] Use AtomicBoolean instead of synchronize the whole method --- .../com/loopj/android/http/ArgsUtils.java | 35 ------------------- .../com/loopj/android/http/AssertUtils.java | 34 ------------------ .../loopj/android/http/AsyncHttpRequest.java | 34 +++++++++--------- .../http/AsyncHttpResponseHandler.java | 4 +-- 4 files changed, 18 insertions(+), 89 deletions(-) delete mode 100644 library/src/main/java/com/loopj/android/http/ArgsUtils.java delete mode 100644 library/src/main/java/com/loopj/android/http/AssertUtils.java diff --git a/library/src/main/java/com/loopj/android/http/ArgsUtils.java b/library/src/main/java/com/loopj/android/http/ArgsUtils.java deleted file mode 100644 index 990a0dcb5..000000000 --- a/library/src/main/java/com/loopj/android/http/ArgsUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -/** - * Internal class, used to check non-private method's args, make sure method contract is met. - */ -class ArgsUtils { - - private ArgsUtils() { - } - - public static T notNull(final T argument, final String name) { - if (argument == null) { - throw new IllegalArgumentException(name + " should not be null!"); - } - return argument; - } -} diff --git a/library/src/main/java/com/loopj/android/http/AssertUtils.java b/library/src/main/java/com/loopj/android/http/AssertUtils.java deleted file mode 100644 index ddd7c6e4a..000000000 --- a/library/src/main/java/com/loopj/android/http/AssertUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -/** - * Internal class, used to make some asserts, throw AssertError if asserts fail. - */ -class AssertUtils { - - private AssertUtils() { - } - - public static void asserts(final boolean expression, final String failedMessage) { - if (!expression) { - throw new AssertionError(failedMessage); - } - } -} diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index b2548cfb9..f164ab2d8 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.UnknownHostException; +import java.util.concurrent.atomic.AtomicBoolean; /** * Internal class, representing the HttpRequest, done in asynchronous manner @@ -39,16 +40,16 @@ public class AsyncHttpRequest implements Runnable { private final HttpUriRequest request; private final ResponseHandlerInterface responseHandler; private int executionCount; - private boolean isCancelled; + private final AtomicBoolean isCancelled = new AtomicBoolean(); private boolean cancelIsNotified; - private boolean isFinished; + private volatile boolean isFinished; private boolean isRequestPreProcessed; public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) { - this.client = ArgsUtils.notNull(client, "client"); - this.context = ArgsUtils.notNull(context, "context"); - this.request = ArgsUtils.notNull(request, "request"); - this.responseHandler = ArgsUtils.notNull(responseHandler, "responseHandler"); + this.client = Utils.notNull(client, "client"); + this.context = Utils.notNull(context, "context"); + this.request = Utils.notNull(request, "request"); + this.responseHandler = Utils.notNull(responseHandler, "responseHandler"); } /** @@ -126,7 +127,7 @@ public void run() { // Carry out post-processing for this request. onPostProcessRequest(this); - setFinished(true); + isFinished = true; } private void makeRequest() throws IOException { @@ -207,30 +208,27 @@ private void makeRequestWithRetries() throws IOException { throw (cause); } - public synchronized boolean isCancelled() { - if (isCancelled) { + public boolean isCancelled() { + boolean cancelled = isCancelled.get(); + if (cancelled) { sendCancelNotification(); } - return isCancelled; + return cancelled; } private synchronized void sendCancelNotification() { - if (!isFinished && isCancelled && !cancelIsNotified) { + if (!isFinished && isCancelled.get() && !cancelIsNotified) { cancelIsNotified = true; responseHandler.sendCancelMessage(); } } - private synchronized void setFinished(boolean finished) { - isFinished = finished; - } - - public synchronized boolean isDone() { + public boolean isDone() { return isCancelled() || isFinished; } - public synchronized boolean cancel(boolean mayInterruptIfRunning) { - isCancelled = true; + public boolean cancel(boolean mayInterruptIfRunning) { + isCancelled.set(true); request.abort(); return isCancelled(); } diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 6943584af..1419cf3a2 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -357,7 +357,7 @@ protected void sendMessage(Message msg) { if (getUseSynchronousMode() || handler == null) { handleMessage(msg); } else if (!Thread.currentThread().isInterrupted()) { // do not send messages if request has been cancelled - AssertUtils.asserts(handler != null, "handler should not be null!"); + Utils.asserts(handler != null, "handler should not be null!"); handler.sendMessage(msg); } } @@ -374,7 +374,7 @@ protected void postRunnable(Runnable runnable) { runnable.run(); } else { // Otherwise, run on provided handler - AssertUtils.asserts(handler != null, "handler should not be null!"); + Utils.asserts(handler != null, "handler should not be null!"); handler.post(runnable); } } From 29afb2c389341e58086dfddbc235e6682dcc1e0d Mon Sep 17 00:00:00 2001 From: Xiaowei Zhao Date: Wed, 20 Aug 2014 23:10:01 +0800 Subject: [PATCH 004/167] Add missed Utils.java --- .../java/com/loopj/android/http/Utils.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 library/src/main/java/com/loopj/android/http/Utils.java diff --git a/library/src/main/java/com/loopj/android/http/Utils.java b/library/src/main/java/com/loopj/android/http/Utils.java new file mode 100644 index 000000000..50d013c4b --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/Utils.java @@ -0,0 +1,38 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.loopj.android.http; + +class Utils { + + private Utils() { + } + + public static void asserts(final boolean expression, final String failedMessage) { + if (!expression) { + throw new AssertionError(failedMessage); + } + } + + public static T notNull(final T argument, final String name) { + if (argument == null) { + throw new IllegalArgumentException(name + " should not be null!"); + } + return argument; + } +} From ef0698e937fec801fb0a6e068aa1e236a0aacb1e Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 14 Nov 2014 21:52:40 +0100 Subject: [PATCH 005/167] Updated build configuration --- .travis.yml | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- library/build.gradle | 6 +++--- sample/build.gradle | 10 +++++----- .../main/res/drawable-hdpi/ic_launcher.png | Bin 9397 -> 3663 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 5237 -> 2627 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 14383 -> 4909 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 7329 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 6982 bytes 10 files changed, 12 insertions(+), 12 deletions(-) mode change 100755 => 100644 sample/src/main/res/drawable-hdpi/ic_launcher.png mode change 100755 => 100644 sample/src/main/res/drawable-mdpi/ic_launcher.png mode change 100755 => 100644 sample/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 sample/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 sample/src/main/res/drawable-xxxhdpi/ic_launcher.png diff --git a/.travis.yml b/.travis.yml index 6f48cc940..87a302508 100755 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,10 @@ language: android jdk: openjdk7 android: components: - - build-tools-19.1.0 + - build-tools-21.1.1 - extra-android-support - extra-android-m2repository - - android-19 + - android-21 licenses: - '.+' script: diff --git a/build.gradle b/build.gradle index 6dcaf5c10..dd730d647 100755 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.12.2' + classpath 'com.android.tools.build:gradle:0.14.2' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 796a51118..27a8a50e9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-bin.zip diff --git a/library/build.gradle b/library/build.gradle index f68a9d92e..697ae5c07 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 19 - buildToolsVersion '19.1' + compileSdkVersion 21 + buildToolsVersion '21.1.1' defaultConfig { minSdkVersion 3 - targetSdkVersion 19 + targetSdkVersion 21 } lintOptions { diff --git a/sample/build.gradle b/sample/build.gradle index 3f4166a7c..02bceb6ac 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.12.2' + classpath 'com.android.tools.build:gradle:0.14.2' } } apply plugin: 'com.android.application' @@ -16,12 +16,12 @@ repositories { } android { - compileSdkVersion 19 - buildToolsVersion '19.1' + compileSdkVersion 21 + buildToolsVersion '21.1.1' defaultConfig { minSdkVersion 3 - targetSdkVersion 19 + targetSdkVersion 21 } compileOptions { @@ -45,6 +45,6 @@ android { } dependencies { - compile 'com.fasterxml.jackson.core:jackson-databind:2.2.3' + compile 'com.fasterxml.jackson.core:jackson-databind:2.4.3' compile project(':library') } diff --git a/sample/src/main/res/drawable-hdpi/ic_launcher.png b/sample/src/main/res/drawable-hdpi/ic_launcher.png old mode 100755 new mode 100644 index 96a442e5b8e9394ccf50bab9988cb2316026245d..d95d16f9e4cd0fbf911bd89d5dd7176b28d6d27b GIT binary patch literal 3663 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 V^IrV4eaHadWbbBo^N+xU{{Te~qq+b9 delta 5212 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 WIxsMIYVlM60000K~D&r0001LVQy?ko6*OE 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 diff --git a/sample/src/main/res/drawable-xxhdpi/ic_launcher.png b/sample/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d75067ca9bacb41b997580a693a538ffd7c147c5 GIT binary patch literal 7329 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 QlL3Ic8V2xsHHWzW0wXeFxc~qF literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-xxxhdpi/ic_launcher.png b/sample/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..927c4a26ce0fdd9d4fe25870aa93e536f3b134bc GIT binary patch literal 6982 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 literal 0 HcmV?d00001 From 4804120403a8b2914516e89082a4aa114255eed1 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 14 Nov 2014 22:01:11 +0100 Subject: [PATCH 006/167] Fixed URLEncoding usage --- .../com/loopj/android/http/AsyncHttpClient.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index dbfa5c79e..7575e7164 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -73,10 +73,10 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; -import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.net.URI; -import java.net.URLEncoder; +import java.net.URL; +import java.net.URLDecoder; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -1229,10 +1229,13 @@ public static String getUrlWithQueryString(boolean shouldEncodeUrl, String url, if (shouldEncodeUrl) { try { - url = URLEncoder.encode(url, "UTF-8"); - } catch (UnsupportedEncodingException e) { + String decodedURL = URLDecoder.decode(url, "UTF-8"); + URL _url = new URL(decodedURL); + URI _uri = new URI(_url.getProtocol(), _url.getUserInfo(), _url.getHost(), _url.getPort(), _url.getPath(), _url.getQuery(), _url.getRef()); + url = _uri.toASCIIString(); + } catch (Exception ex) { // Should not really happen, added just for sake of validity - Log.e(LOG_TAG, "getUrlWithQueryString encoding URL", e); + Log.e(LOG_TAG, "getUrlWithQueryString encoding URL", ex); } } From 28d93466266904d8b8697f990b4a36c3409fa840 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 14 Nov 2014 22:18:11 +0100 Subject: [PATCH 007/167] Fixes #716 --- .../com/loopj/android/http/DataAsyncHttpResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index bea9a929c..d801c9faf 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -30,7 +30,7 @@ public abstract class DataAsyncHttpResponseHandler extends AsyncHttpResponseHandler { private static final String LOG_TAG = "DataAsyncHttpResponseHandler"; - protected static final int PROGRESS_DATA_MESSAGE = 6; + protected static final int PROGRESS_DATA_MESSAGE = 7; /** * Creates a new AsyncHttpResponseHandler From 85ffc37b1e1477930a5dc9ca5b0407dc92d09969 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 14 Nov 2014 23:23:22 +0100 Subject: [PATCH 008/167] Fixes #690 --- .../com/loopj/android/http/FileAsyncHttpResponseHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 13de7fe2f..6a546257d 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -53,6 +53,7 @@ public FileAsyncHttpResponseHandler(File file) { public FileAsyncHttpResponseHandler(File file, boolean append) { super(); AssertUtils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); + AssertUtils.asserts(getTargetFile().getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); this.mFile = file; this.append = append; } From ba5d157acff1d5025506b090ab83d63d0c93fab0 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sat, 15 Nov 2014 11:39:29 +0100 Subject: [PATCH 009/167] Updated changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0566956b0..e1fe1d1ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## 1.4.7 (future version) - Fixed crash when canceling through RequestHandle from UI Thread (NetworkOnMainThreadException) + - Fixed URL encoding feature, that was breaking whole URL, not just path and query parts + - FileAsyncHttpResponseHandler now checks that target file path is available or can be created + - DataAsyncHttpResponseHandler was sending cancel notification instead of progress notification, fixed ## 1.4.6 (released 7. 9. 2014) From 29ba1f0a5d7d9ab875edee59708ba0a38255a798 Mon Sep 17 00:00:00 2001 From: Chris Kruger Date: Tue, 25 Nov 2014 12:20:22 +0800 Subject: [PATCH 010/167] naive implmentation of HTTP method PATCH --- .../loopj/android/http/AsyncHttpClient.java | 70 +++++++++++++++++++ .../com/loopj/android/http/HttpPatch.java | 33 +++++++++ sample/src/main/AndroidManifest.xml | 4 +- .../android/http/sample/PatchSample.java | 68 ++++++++++++++++++ .../http/sample/WaypointsActivity.java | 1 + sample/src/main/res/values/strings.xml | 1 + 6 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 library/src/main/java/com/loopj/android/http/HttpPatch.java create mode 100644 sample/src/main/java/com/loopj/android/http/sample/PatchSample.java diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 7575e7164..2626f9ca6 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1065,7 +1065,77 @@ public RequestHandle put(Context context, String url, Header[] headers, HttpEnti if (headers != null) request.setHeaders(headers); return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); } + + /** + * Perform a HTTP PATCH request, without any parameters. + * + * @param url the URL to send the request to. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle patch(String url, ResponseHandlerInterface responseHandler) { + return patch(null, url, null, responseHandler); + } + /** + * Perform a HTTP PATCH request with parameters. + * + * @param url the URL to send the request to. + * @param params additional PUT parameters or files to send with the request. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle patch(String url, RequestParams params, ResponseHandlerInterface responseHandler) { + return patch(null, url, params, responseHandler); + } + + /** + * Perform a HTTP PATCH request and track the Android Context which initiated the request. + * + * @param context the Android Context which initiated the request. + * @param url the URL to send the request to. + * @param params additional PUT parameters or files to send with the request. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle patch(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) { + return patch(context, url, paramsToEntity(params, responseHandler), null, responseHandler); + } + + /** + * Perform a HTTP PATCH request and track the Android Context which initiated the request. + * + * @param context the Android Context which initiated the request. + * @param url the URL to send the request to. + * @param params additional PUT parameters or files to send with the request. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle patch(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { + return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity), contentType, responseHandler, context); + } + + /** + * Perform a HTTP PATCH request and track the Android Context which initiated the request. And set + * one-time headers for the request + * + * @param context the Android Context which initiated the request. + * @param url the URL to send the request to. + * @param headers set one-time headers for this request + * @param entity a raw {@link HttpEntity} to send with the request, for example, use + * this to send string/json/xml payloads to a server by passing a {@link + * org.apache.http.entity.StringEntity}. + * @param contentType the content type of the payload you are sending, for example + * application/json if sending a json payload. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle patch(Context context, String url, Header[] headers, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { + HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity); + if (headers != null) request.setHeaders(headers); + return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); + } + // [-] HTTP PUT // [+] HTTP DELETE diff --git a/library/src/main/java/com/loopj/android/http/HttpPatch.java b/library/src/main/java/com/loopj/android/http/HttpPatch.java new file mode 100644 index 000000000..f805bc0e3 --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/HttpPatch.java @@ -0,0 +1,33 @@ +package com.loopj.android.http; + +import java.net.URI; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +public final class HttpPatch extends HttpEntityEnclosingRequestBase { + + public final static String METHOD_NAME = "PATCH"; + + public HttpPatch() { + super(); + } + + public HttpPatch(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpPatch(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } + +} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index c3ebb2f1a..a3563f585 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ + @@ -32,6 +33,7 @@ + @@ -44,8 +46,8 @@ - + diff --git a/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java b/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java new file mode 100644 index 000000000..8bd8ab1e2 --- /dev/null +++ b/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java @@ -0,0 +1,68 @@ +package com.loopj.android.http.sample; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.RequestHandle; +import com.loopj.android.http.ResponseHandlerInterface; + +public class PatchSample extends SampleParentActivity { + + private static final String LOG_TAG = "PatchSample"; + + @Override + public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { + return client.patch(this, URL, entity, null, responseHandler); + } + + @Override + public int getSampleTitle() { + return R.string.title_patch_sample; + } + + @Override + public boolean isRequestBodyAllowed() { + return false; + } + + @Override + public boolean isRequestHeadersAllowed() { + return false; + } + + @Override + public String getDefaultURL() { + return PROTOCOL + "httpbin.org/patch"; + } + + @Override + public ResponseHandlerInterface getResponseHandler() { + return new AsyncHttpResponseHandler() { + @Override + public void onStart() { + clearOutputs(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] response) { + debugHeaders(LOG_TAG, headers); + debugStatusCode(LOG_TAG, statusCode); + debugResponse(LOG_TAG, new String(response)); + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { + debugHeaders(LOG_TAG, headers); + debugStatusCode(LOG_TAG, statusCode); + debugThrowable(LOG_TAG, e); + if (errorResponse != null) { + debugResponse(LOG_TAG, new String(errorResponse)); + } + } + }; + } + + +} diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java index 099dc1344..c8d6f0639 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java @@ -35,6 +35,7 @@ public class WaypointsActivity extends ListActivity { new SampleConfig(R.string.title_post_sample, PostSample.class), new SampleConfig(R.string.title_delete_sample, DeleteSample.class), new SampleConfig(R.string.title_put_sample, PutSample.class), + new SampleConfig(R.string.title_patch_sample, PatchSample.class), new SampleConfig(R.string.title_json_sample, JsonSample.class), new SampleConfig(R.string.title_json_streamer_sample, JsonStreamerSample.class), new SampleConfig(R.string.title_sax_example, SaxSample.class), diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index f8465168b..5cb9cd6c7 100755 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -21,6 +21,7 @@ POST JSON using streamer POST PUT + PATCH DELETE GET to File GET binary data From 305aa67b576d9418aa811acfa868492f33854f37 Mon Sep 17 00:00:00 2001 From: Chris Kruger Date: Tue, 25 Nov 2014 12:28:46 +0800 Subject: [PATCH 011/167] fleshed out comments --- .../com/loopj/android/http/HttpPatch.java | 63 ++++++++++++------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/HttpPatch.java b/library/src/main/java/com/loopj/android/http/HttpPatch.java index f805bc0e3..a81cc2c54 100644 --- a/library/src/main/java/com/loopj/android/http/HttpPatch.java +++ b/library/src/main/java/com/loopj/android/http/HttpPatch.java @@ -1,33 +1,54 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package com.loopj.android.http; import java.net.URI; - import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +/** + * The current Android (API level 21) bundled version of the Apache Http Client does not implement + * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. + * This implementation can and should go away when the official solution arrives. + */ public final class HttpPatch extends HttpEntityEnclosingRequestBase { - public final static String METHOD_NAME = "PATCH"; - - public HttpPatch() { - super(); - } - - public HttpPatch(final URI uri) { - super(); - setURI(uri); - } - - /** - * @throws IllegalArgumentException if the uri is invalid. - */ - public HttpPatch(final String uri) { + public final static String METHOD_NAME = "PATCH"; + + public HttpPatch() { super(); - setURI(URI.create(uri)); } - @Override - public String getMethod() { - return METHOD_NAME; - } + public HttpPatch(final URI uri) { + super(); + setURI(uri); + } + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpPatch(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } } From 474b36afe3b3716ec994739bf27a350611cbec4e Mon Sep 17 00:00:00 2001 From: mareksebera Date: Wed, 26 Nov 2014 09:57:46 +0100 Subject: [PATCH 012/167] Accessing getTargetFile() before value is assigned, Closing #743 --- .../com/loopj/android/http/FileAsyncHttpResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 6a546257d..5a2fc84a3 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -53,7 +53,7 @@ public FileAsyncHttpResponseHandler(File file) { public FileAsyncHttpResponseHandler(File file, boolean append) { super(); AssertUtils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); - AssertUtils.asserts(getTargetFile().getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); + AssertUtils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); this.mFile = file; this.append = append; } From d3d577a1b756e45d1f0d9edfa544ee697f40d7ce Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 20:32:01 +0100 Subject: [PATCH 013/167] Added legal NOTICE for including codebase from Apache HttpClient implementation --- CHANGELOG.md | 1 + NOTICE.txt | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 NOTICE.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fe1d1ed..03244ff37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fixed URL encoding feature, that was breaking whole URL, not just path and query parts - FileAsyncHttpResponseHandler now checks that target file path is available or can be created - DataAsyncHttpResponseHandler was sending cancel notification instead of progress notification, fixed + - Added support for HTTP PATCH requests ## 1.4.6 (released 7. 9. 2014) diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 000000000..283826a13 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,6 @@ +Android Async Http Client library +Copyright (c) 2011-2014 James Smith +http://loopj.com + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). From 6cc866fd38c9f65ca7b58c7ecabcaa40355aa8be Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 20:37:04 +0100 Subject: [PATCH 014/167] Fixed migration from AssertUtils class to Utils --- .../loopj/android/http/FileAsyncHttpResponseHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 5a2fc84a3..407857256 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -52,8 +52,8 @@ public FileAsyncHttpResponseHandler(File file) { */ public FileAsyncHttpResponseHandler(File file, boolean append) { super(); - AssertUtils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); - AssertUtils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); + Utils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); + Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); this.mFile = file; this.append = append; } @@ -85,7 +85,7 @@ public boolean deleteTargetFile() { * @return temporary file or null if creating file failed */ protected File getTemporaryFile(Context context) { - AssertUtils.asserts(context != null, "Tried creating temporary file without having Context"); + Utils.asserts(context != null, "Tried creating temporary file without having Context"); try { // not effective in release mode assert context != null; From 1a106947dcafdcc605cc60520675f6ff960afa58 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 20:50:39 +0100 Subject: [PATCH 015/167] Fixed javadocs for createConnectionManager, and asserted error when custom implemenation would return null --- .../loopj/android/http/AsyncHttpClient.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 2626f9ca6..dcbded5ca 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -49,6 +49,7 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.params.ClientPNames; import org.apache.http.client.protocol.ClientContext; +import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.params.ConnPerRouteBean; import org.apache.http.conn.params.ConnRoutePNames; @@ -237,7 +238,8 @@ public AsyncHttpClient(SchemeRegistry schemeRegistry) { HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); - ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry); + ClientConnectionManager cm = createConnectionManager(schemeRegistry, httpParams); + Utils.asserts(cm != null, "Custom implementation of #createConnectionManager(SchemeRegistry, BasicHttpParams) returned null"); threadPool = getDefaultThreadPool(); requestMap = Collections.synchronizedMap(new WeakHashMap>()); @@ -382,6 +384,17 @@ protected ExecutorService getDefaultThreadPool() { return Executors.newCachedThreadPool(); } + /** + * Provided so it is easier for developers to provide custom ThreadSafeClientConnManager implementation + * + * @param schemeRegistry SchemeRegistry, usually provided by {@link #getDefaultSchemeRegistry(boolean, int, int)} + * @param httpParams BasicHttpParams + * @return ClientConnectionManager instance + */ + protected ClientConnectionManager createConnectionManager(SchemeRegistry schemeRegistry, BasicHttpParams httpParams) { + return new ThreadSafeClientConnManager(httpParams, schemeRegistry); + } + /** * Simple interface method, to enable or disable redirects. If you set manually RedirectHandler * on underlying HttpClient, effects of this method will be canceled.

 

Default @@ -1065,7 +1078,7 @@ public RequestHandle put(Context context, String url, Header[] headers, HttpEnti if (headers != null) request.setHeaders(headers); return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); } - + /** * Perform a HTTP PATCH request, without any parameters. * @@ -1101,20 +1114,19 @@ public RequestHandle patch(String url, RequestParams params, ResponseHandlerInte public RequestHandle patch(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) { return patch(context, url, paramsToEntity(params, responseHandler), null, responseHandler); } - + /** * Perform a HTTP PATCH request and track the Android Context which initiated the request. * * @param context the Android Context which initiated the request. * @param url the URL to send the request to. - * @param params additional PUT parameters or files to send with the request. * @param responseHandler the response handler instance that should handle the response. * @return RequestHandle of future request process */ public RequestHandle patch(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity), contentType, responseHandler, context); } - + /** * Perform a HTTP PATCH request and track the Android Context which initiated the request. And set * one-time headers for the request @@ -1131,11 +1143,11 @@ public RequestHandle patch(Context context, String url, HttpEntity entity, Strin * @return RequestHandle of future request process */ public RequestHandle patch(Context context, String url, Header[] headers, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity); - if (headers != null) request.setHeaders(headers); - return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); + HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity); + if (headers != null) request.setHeaders(headers); + return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); } - + // [-] HTTP PUT // [+] HTTP DELETE From 2e688e03d9e8d9e062de9e2f2ab4a0dbefdc1358 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 21:01:24 +0100 Subject: [PATCH 016/167] Fixed various javadoc, lint and documentation issues --- .../http/SaxAsyncHttpResponseHandler.java | 4 +--- .../java/com/loopj/android/http/Utils.java | 18 ++++++++++++++++++ .../http/sample/RangeResponseSample.java | 17 +++++++++++------ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index f4663b7bb..c544f648d 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -101,9 +101,7 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { rssReader.setContentHandler(handler); inputStreamReader = new InputStreamReader(instream, DEFAULT_CHARSET); rssReader.parse(new InputSource(inputStreamReader)); - } catch (SAXException e) { - Log.e(LOG_TAG, "getResponseData exception", e); - } catch (ParserConfigurationException e) { + } catch (SAXException | ParserConfigurationException e) { Log.e(LOG_TAG, "getResponseData exception", e); } finally { AsyncHttpClient.silentCloseInputStream(instream); diff --git a/library/src/main/java/com/loopj/android/http/Utils.java b/library/src/main/java/com/loopj/android/http/Utils.java index 50d013c4b..196d5a46b 100644 --- a/library/src/main/java/com/loopj/android/http/Utils.java +++ b/library/src/main/java/com/loopj/android/http/Utils.java @@ -18,17 +18,35 @@ package com.loopj.android.http; +/** + * Provides general assert utils, which are stripped by Android SDK on + * compile/runtime, to work on release builds + */ class Utils { private Utils() { } + /** + * Will throw AssertionError, if expression is not true + * + * @param expression result of your asserted condition + * @param failedMessage message to be included in error log + * @throws java.lang.AssertionError + */ public static void asserts(final boolean expression, final String failedMessage) { if (!expression) { throw new AssertionError(failedMessage); } } + /** + * Will throw IllegalArgumentException if provided object is null on runtime + * + * @param argument object that should be asserted as not null + * @param name name of the object asserted + * @throws java.lang.IllegalArgumentException + */ public static T notNull(final T argument, final String name) { if (argument == null) { throw new IllegalArgumentException(name + " should not be null!"); diff --git a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java index 3daf055c1..274b5e2bf 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java @@ -21,16 +21,19 @@ import android.os.Bundle; import android.util.Log; import android.widget.Toast; + import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.RangeFileAsyncHttpResponseHandler; import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import java.io.File; -import java.io.IOException; + import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.methods.HttpUriRequest; +import java.io.File; +import java.io.IOException; + /** * This sample demonstrates use of {@link RangeFileAsyncHttpResponseHandler} to * download a remote file in multiple requests. While this response handler @@ -71,7 +74,9 @@ protected void onDestroy() { // Remove temporary file. if (file != null) { - file.delete(); + if (!file.delete()) { + Log.e(LOG_TAG, String.format("Couldn't remove temporary file in path: %s", file.getAbsolutePath())); + } file = null; } } @@ -133,9 +138,9 @@ public void onSuccess(int statusCode, Header[] headers, File file) { // Is the content length known? if (!supportsRange || fileSize < 1) { Toast.makeText( - RangeResponseSample.this, - "Unable to determine remote file's size, or\nremote server doesn't support ranges", - Toast.LENGTH_LONG + RangeResponseSample.this, + "Unable to determine remote file's size, or\nremote server doesn't support ranges", + Toast.LENGTH_LONG ).show(); } } From 390b6f5e47bdd1470b6c4e434b9de8ca9d16cb00 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 21:17:04 +0100 Subject: [PATCH 017/167] Fixed regression bug in support of JDK6 --- .../com/loopj/android/http/SaxAsyncHttpResponseHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index c544f648d..f4663b7bb 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -101,7 +101,9 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { rssReader.setContentHandler(handler); inputStreamReader = new InputStreamReader(instream, DEFAULT_CHARSET); rssReader.parse(new InputSource(inputStreamReader)); - } catch (SAXException | ParserConfigurationException e) { + } catch (SAXException e) { + Log.e(LOG_TAG, "getResponseData exception", e); + } catch (ParserConfigurationException e) { Log.e(LOG_TAG, "getResponseData exception", e); } finally { AsyncHttpClient.silentCloseInputStream(instream); From 993a03acccc7982549e6d45ec66bc11b47482cc0 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 21:36:06 +0100 Subject: [PATCH 018/167] Fixed mkdirs assertion, mkdirs can return false if directories already exist --- .../com/loopj/android/http/FileAsyncHttpResponseHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 407857256..99445d874 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -53,7 +53,9 @@ public FileAsyncHttpResponseHandler(File file) { public FileAsyncHttpResponseHandler(File file, boolean append) { super(); Utils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); - Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); + if (!file.getParentFile().isDirectory()) { + Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); + } this.mFile = file; this.append = append; } From f6606701d65cfa612af01830677b73f2a9d791a5 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 5 Dec 2014 21:56:00 +0100 Subject: [PATCH 019/167] Updated changelog [skip-ci] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03244ff37..948f7b1f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - FileAsyncHttpResponseHandler now checks that target file path is available or can be created - DataAsyncHttpResponseHandler was sending cancel notification instead of progress notification, fixed - Added support for HTTP PATCH requests + - Fixed Assert exception when mkdirs in FileAsyncHttpResponseHandler tries to create dirs that already exists + - Provided option to easily override ClientConnectionManager provision in AsyncHttpClient ## 1.4.6 (released 7. 9. 2014) From 7cc6b8de628757037c857f27a8987ada7242b116 Mon Sep 17 00:00:00 2001 From: Sabi Date: Sat, 6 Dec 2014 12:03:08 -0500 Subject: [PATCH 020/167] sending raw HttpEntities to Get of Delete request like for JSON payloads/queries --- .../loopj/android/http/AsyncHttpClient.java | 37 ++++++++++++- .../com/loopj/android/http/HttpDelete.java | 54 ++++++++++++++++++ .../java/com/loopj/android/http/HttpGet.java | 55 +++++++++++++++++++ 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 library/src/main/java/com/loopj/android/http/HttpDelete.java create mode 100644 library/src/main/java/com/loopj/android/http/HttpGet.java diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index dcbded5ca..c11a89c20 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -40,9 +40,7 @@ import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.RedirectHandler; -import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; @@ -69,6 +67,7 @@ import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.SyncBasicHttpContext; +import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; @@ -901,6 +900,23 @@ public RequestHandle get(Context context, String url, Header[] headers, RequestP context); } + /** + * Perform a HTTP GET request and track the Android Context which initiated the request. + * + * @param context the Android Context which initiated the request. + * @param url the URL to send the request to. + * @param entity a raw {@link org.apache.http.HttpEntity} to send with the request, for + * example, use this to send string/json/xml payloads to a server by + * passing a {@link org.apache.http.entity.StringEntity}. + * @param contentType the content type of the payload you are sending, for example + * application/json if sending a json payload. + * @param responseHandler the response ha ndler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle get(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { + return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpGet(URI.create(url).normalize()), entity), contentType, responseHandler, context); + } + // [-] HTTP GET // [+] HTTP POST @@ -1206,6 +1222,23 @@ public RequestHandle delete(Context context, String url, Header[] headers, Reque return sendRequest(httpClient, httpContext, httpDelete, null, responseHandler, context); } + /** + * Perform a HTTP DELETE request and track the Android Context which initiated the request. + * + * @param context the Android Context which initiated the request. + * @param url the URL to send the request to. + * @param entity a raw {@link org.apache.http.HttpEntity} to send with the request, for + * example, use this to send string/json/xml payloads to a server by + * passing a {@link org.apache.http.entity.StringEntity}. + * @param contentType the content type of the payload you are sending, for example + * application/json if sending a json payload. + * @param responseHandler the response ha ndler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle delete(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { + return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpDelete(URI.create(url).normalize()), entity), contentType, responseHandler, context); + } + // [-] HTTP DELETE /** diff --git a/library/src/main/java/com/loopj/android/http/HttpDelete.java b/library/src/main/java/com/loopj/android/http/HttpDelete.java new file mode 100644 index 000000000..15df2f54f --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/HttpDelete.java @@ -0,0 +1,54 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.loopj.android.http; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +import java.net.URI; + +/** + * The current Android (API level 21) bundled version of the Apache Http Client does not implement + * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. + * This implementation can and should go away when the official solution arrives. + */ +public final class HttpDelete extends HttpEntityEnclosingRequestBase { + public final static String METHOD_NAME = "DELETE"; + + public HttpDelete() { + super(); + } + + public HttpDelete(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpDelete(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} diff --git a/library/src/main/java/com/loopj/android/http/HttpGet.java b/library/src/main/java/com/loopj/android/http/HttpGet.java new file mode 100644 index 000000000..522a20cbd --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/HttpGet.java @@ -0,0 +1,55 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.loopj.android.http; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +import java.net.URI; + +/** + * The current Android (API level 21) bundled version of the Apache Http Client does not implement + * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. + * This implementation can and should go away when the official solution arrives. + */ +public final class HttpGet extends HttpEntityEnclosingRequestBase { + + public final static String METHOD_NAME = "GET"; + + public HttpGet() { + super(); + } + + public HttpGet(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpGet(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} From 4f73e516842d451e0a671c7db2bb274907f36827 Mon Sep 17 00:00:00 2001 From: Sabi Date: Sat, 6 Dec 2014 12:09:28 -0500 Subject: [PATCH 021/167] comments updated --- .../src/main/java/com/loopj/android/http/AsyncHttpClient.java | 1 - library/src/main/java/com/loopj/android/http/HttpDelete.java | 3 ++- library/src/main/java/com/loopj/android/http/HttpGet.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index c11a89c20..2acb84e00 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -67,7 +67,6 @@ import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.SyncBasicHttpContext; -import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; diff --git a/library/src/main/java/com/loopj/android/http/HttpDelete.java b/library/src/main/java/com/loopj/android/http/HttpDelete.java index 15df2f54f..7bd0d10b2 100644 --- a/library/src/main/java/com/loopj/android/http/HttpDelete.java +++ b/library/src/main/java/com/loopj/android/http/HttpDelete.java @@ -24,7 +24,8 @@ /** * The current Android (API level 21) bundled version of the Apache Http Client does not implement - * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. + * a HttpEntityEnclosingRequestBase type of HTTP DELETE method. + * Until the Android version is updated this can serve in it's stead. * This implementation can and should go away when the official solution arrives. */ public final class HttpDelete extends HttpEntityEnclosingRequestBase { diff --git a/library/src/main/java/com/loopj/android/http/HttpGet.java b/library/src/main/java/com/loopj/android/http/HttpGet.java index 522a20cbd..880f3c76f 100644 --- a/library/src/main/java/com/loopj/android/http/HttpGet.java +++ b/library/src/main/java/com/loopj/android/http/HttpGet.java @@ -24,7 +24,8 @@ /** * The current Android (API level 21) bundled version of the Apache Http Client does not implement - * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. + * a HttpEntityEnclosingRequestBase type of HTTP GET method. + * Until the Android version is updated this can serve in it's stead. * This implementation can and should go away when the official solution arrives. */ public final class HttpGet extends HttpEntityEnclosingRequestBase { From de10c013b2acbc41afbd5f9157b94a3edca1879c Mon Sep 17 00:00:00 2001 From: mareksebera Date: Mon, 8 Dec 2014 14:02:40 +0100 Subject: [PATCH 022/167] Passing directory into FileAsyncHttpResponseHandler instead of file is not supported yet --- .../com/loopj/android/http/FileAsyncHttpResponseHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 99445d874..1a11a1a08 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -53,6 +53,7 @@ public FileAsyncHttpResponseHandler(File file) { public FileAsyncHttpResponseHandler(File file, boolean append) { super(); Utils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); + Utils.asserts(!file.isDirectory(), "File passed into FileAsyncHttpResponseHandler constructor must not point to directory"); if (!file.getParentFile().isDirectory()) { Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); } From 76003fd17015c1461a1b652390d22938b1479eb4 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Fri, 19 Dec 2014 21:33:23 +0100 Subject: [PATCH 023/167] Enable responses to be fired on the same thread which was used in the request. This is handy in situations where more work needs to be done on the thread which doesn't require UI changes, like for example processing JSON responses, parsing images, etc. --- .../loopj/android/http/AsyncHttpClient.java | 2 +- .../http/AsyncHttpResponseHandler.java | 20 +++++++++++++++++++ .../http/BaseJsonHttpResponseHandler.java | 4 ++-- .../android/http/JsonHttpResponseHandler.java | 4 ++-- .../http/ResponseHandlerInterface.java | 16 +++++++++++++++ 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index dcbded5ca..e0222ac95 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1245,7 +1245,7 @@ protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpCo throw new IllegalArgumentException("ResponseHandler must not be null"); } - if (responseHandler.getUseSynchronousMode()) { + if (responseHandler.getUseSynchronousMode() && !responseHandler.getUsePoolThread()) { throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead."); } diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 1419cf3a2..23040bba5 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -97,6 +97,7 @@ public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterfa private String responseCharset = DEFAULT_CHARSET; private Handler handler; private boolean useSynchronousMode; + private boolean usePoolThread; private URI requestURI = null; private Header[] requestHeaders = null; @@ -164,6 +165,23 @@ public void setUseSynchronousMode(boolean sync) { useSynchronousMode = sync; } + @Override + public boolean getUsePoolThread() { + return usePoolThread; + } + + @Override + public void setUsePoolThread(boolean pool) { + // If pool thread is to be used, there's no point in keeping a reference + // to the looper and no need for a handler. + if (pool) { + looper = null; + handler = null; + } + + usePoolThread = pool; + } + /** * Sets the charset for the response string. If not set, the default is UTF-8. * @@ -196,6 +214,8 @@ public AsyncHttpResponseHandler(Looper looper) { this.looper = looper == null ? Looper.myLooper() : looper; // Use asynchronous mode by default. setUseSynchronousMode(false); + // Do not use the pool's thread to run the handler. + setUsePoolThread(false); } /** diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java index dae49c599..bbec96956 100755 --- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java @@ -97,7 +97,7 @@ public void run() { } } }; - if (!getUseSynchronousMode()) { + if (!getUseSynchronousMode() && !getUsePoolThread()) { new Thread(parser).start(); } else { // In synchronous mode everything should be run on one thread @@ -133,7 +133,7 @@ public void run() { } } }; - if (!getUseSynchronousMode()) { + if (!getUseSynchronousMode() && !getUsePoolThread()) { new Thread(parser).start(); } else { // In synchronous mode everything should be run on one thread diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index b12afce68..52663a072 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -144,7 +144,7 @@ public void run() { } } }; - if (!getUseSynchronousMode()) { + if (!getUseSynchronousMode() && !getUsePoolThread()) { new Thread(parser).start(); } else { // In synchronous mode everything should be run on one thread @@ -189,7 +189,7 @@ public void run() { } } }; - if (!getUseSynchronousMode()) { + if (!getUseSynchronousMode() && !getUsePoolThread()) { new Thread(parser).start(); } else { // In synchronous mode everything should be run on one thread diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index 193f44fea..6660683c8 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -128,6 +128,22 @@ public interface ResponseHandlerInterface { */ boolean getUseSynchronousMode(); + /** + * Sets whether the handler should be executed on the pool's thread or the + * UI thread + * + * @param usePoolThread if the ResponseHandler should run on pool's thread + */ + void setUsePoolThread(boolean usePoolThread); + + /** + * Returns whether the handler should be executed on the pool's thread + * or the UI thread + * + * @return boolean if the ResponseHandler should run on pool's thread + */ + boolean getUsePoolThread(); + /** * This method is called once by the system when the response is about to be * processed by the system. The library makes sure that a single response From 0c2f1a79ca9b8468e7089a50cd22323f99cfb42f Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sat, 20 Dec 2014 13:19:24 +0100 Subject: [PATCH 024/167] Sample activity to demonstrate use of Pool Thread in responses. --- sample/src/main/AndroidManifest.xml | 6 +- .../http/sample/UsePoolThreadSample.java | 116 ++++++++++++++++++ .../http/sample/WaypointsActivity.java | 3 +- sample/src/main/res/values/strings.xml | 1 + 4 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index a3563f585..1d180c460 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -11,12 +11,14 @@ android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> + + @@ -46,8 +48,10 @@ + + - + diff --git a/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java new file mode 100644 index 000000000..9c7aaa4db --- /dev/null +++ b/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java @@ -0,0 +1,116 @@ +package com.loopj.android.http.sample; + +import android.util.Log; +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.ResponseHandlerInterface; +import static com.loopj.android.http.sample.SampleParentActivity.LIGHTGREEN; +import java.io.File; + +import org.apache.http.Header; + +public class UsePoolThreadSample extends GetSample { + + private static final String LOG_TAG = "UsePoolThreadSample"; + + @Override + public String getDefaultURL() { + return PROTOCOL + "httpbin.org/bytes/1024000"; + } + + @Override + public boolean isRequestHeadersAllowed() { + return false; + } + + @Override + public int getSampleTitle() { + return R.string.title_use_pool_thread; + } + + @Override + public ResponseHandlerInterface getResponseHandler() { + return new UsePoolThreadResponseHandler(); + } + + private class UsePoolThreadResponseHandler extends AsyncHttpResponseHandler { + + private final File destFile; + + public UsePoolThreadResponseHandler() { + super(); + + // Destination file to save the downloaded bytes to. + destFile = getRandomCacheFile(); + Log.d(LOG_TAG, "Bytes will be saved in file: " + destFile.getAbsolutePath()); + + // We wish to use the same pool thread to run the response. + setUsePoolThread(true); + } + + @Override + public void onSuccess(final int statusCode, final Header[] headers, final byte[] responseBody) { + // Response body includes 1MB of data, and it might take few + // milliseconds, maybe a second or two on old devices, to save it in + // the filesystem. However, since this callback method is running + // within the pool thread's execution scope, the UI thread will be + // relaxed to continue its work of updating the UI while this + // handler saves the bytes on disk. + + // Save the response body's bytes on disk. + saveBytesOnDisk(destFile, responseBody); + + // This callback is now running within the pool thread execution + // scope and not within Android's UI thread, so if we must update + // the UI, we'll have to dispatch a runnable to the UI thread. + runOnUiThread(new Runnable() { + + @Override + public void run() { + debugStatusCode(LOG_TAG, statusCode); + debugHeaders(LOG_TAG, headers); + if (responseBody != null) { + addView(getColoredView(LIGHTGREEN, "Request succeeded (" + statusCode + "): (bytes=" + destFile.length() + "), path: " + destFile.getAbsolutePath())); + } + } + }); + } + + @Override + public void onFailure(final int statusCode, final Header[] headers, final byte[] responseBody, final Throwable error) { + // This callback is now running within the pool thread execution + // scope and not within Android's UI thread, so if we must update + // the UI, we'll have to dispatch a runnable to the UI thread. + runOnUiThread(new Runnable() { + + @Override + public void run() { + debugStatusCode(LOG_TAG, statusCode); + debugHeaders(LOG_TAG, headers); + debugThrowable(LOG_TAG, error); + if (responseBody != null) { + addView(getColoredView(LIGHTGREEN, "Download interrupted (" + statusCode + "): (bytes=" + responseBody.length + "), path: " + destFile.getAbsolutePath())); + } + } + }); + } + + private File getRandomCacheFile() { + File dir = getExternalCacheDir(); + if(dir == null) { + dir = getCacheDir(); + if(dir == null) { + dir = getFilesDir(); + } + } + + return new File(dir, "sample-" + System.currentTimeMillis() + ".bin"); + } + + private void saveBytesOnDisk(File destination, byte[] bytes) { + // TODO: Spin your own implementation to save the bytes on disk/SD card. + if(bytes != null && destination != null) { + Log.d(LOG_TAG, "Saved " + bytes.length + " bytes into file: " + destination.getAbsolutePath()); + } + } + } +} diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java index c8d6f0639..23ad87644 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java @@ -57,7 +57,8 @@ public class WaypointsActivity extends ListActivity { new SampleConfig(R.string.title_pre_post_processing, PrePostProcessingSample.class), new SampleConfig(R.string.title_content_type_http_entity, ContentTypeForHttpEntitySample.class), new SampleConfig(R.string.title_resume_download, ResumeDownloadSample.class), - new SampleConfig(R.string.title_digest_auth, DigestAuthSample.class) + new SampleConfig(R.string.title_digest_auth, DigestAuthSample.class), + new SampleConfig(R.string.title_use_pool_thread, UsePoolThreadSample.class) }; @Override diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 5cb9cd6c7..83bb24e4a 100755 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -44,4 +44,5 @@ Content-Type with HttpEntity Resuming Download Digest Authentication + Use Pool Thread in Response From b173af365c44643465cbc1102fe0d6cae0091766 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 21 Dec 2014 12:28:10 +0100 Subject: [PATCH 025/167] Add another constructor for controlling usePoolThread. No need to construct a looper, or get the current looper, when, in essence, we don't wish to use one at all. --- .../http/AsyncHttpResponseHandler.java | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 23040bba5..a61d456e7 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -103,6 +103,50 @@ public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterfa private Header[] requestHeaders = null; private Looper looper = null; + /** + * Creates a new AsyncHttpResponseHandler + */ + public AsyncHttpResponseHandler() { + this(null); + } + + /** + * Creates a new AsyncHttpResponseHandler with a user-supplied looper. If + * the passed looper is null, the looper attached to the current thread will + * be used. + * + * @param looper The looper to work with + */ + public AsyncHttpResponseHandler(Looper looper) { + this.looper = looper == null ? Looper.myLooper() : looper; + + // Use asynchronous mode by default. + setUseSynchronousMode(false); + + // Do not use the pool's thread to fire callbacks by default. + setUsePoolThread(false); + } + + /** + * Creates a new AsyncHttpResponseHandler and decide whether the callbacks + * will be fired on current thread's looper or the pool thread's. + * + * @param usePoolThread Whether to use the pool's thread to fire callbacks + */ + public AsyncHttpResponseHandler(boolean usePoolThread) { + // Whether to use the pool's thread to fire callbacks. + setUsePoolThread(usePoolThread); + + // When using the pool's thread, there's no sense in having a looper. + if (!getUsePoolThread()) { + // Use the current thread's looper. + this.looper = Looper.myLooper(); + + // Use asynchronous mode by default. + setUseSynchronousMode(false); + } + } + @Override public URI getRequestURI() { return this.requestURI; @@ -196,28 +240,6 @@ public String getCharset() { return this.responseCharset == null ? DEFAULT_CHARSET : this.responseCharset; } - /** - * Creates a new AsyncHttpResponseHandler - */ - public AsyncHttpResponseHandler() { - this(null); - } - - /** - * Creates a new AsyncHttpResponseHandler with a user-supplied looper. If - * the passed looper is null, the looper attached to the current thread will - * be used. - * - * @param looper The looper to work with - */ - public AsyncHttpResponseHandler(Looper looper) { - this.looper = looper == null ? Looper.myLooper() : looper; - // Use asynchronous mode by default. - setUseSynchronousMode(false); - // Do not use the pool's thread to run the handler. - setUsePoolThread(false); - } - /** * Fired when the request progress, override to handle in your own code * From 5b1abfbfff71bc23c12bdb908733844ffe4d3621 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sun, 21 Dec 2014 14:50:29 +0100 Subject: [PATCH 026/167] Fixed Lint issue in UsePoolThreadSample --- .../android/http/sample/UsePoolThreadSample.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java index 9c7aaa4db..45dd61fdd 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java @@ -1,13 +1,14 @@ package com.loopj.android.http.sample; import android.util.Log; + import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.ResponseHandlerInterface; -import static com.loopj.android.http.sample.SampleParentActivity.LIGHTGREEN; -import java.io.File; import org.apache.http.Header; +import java.io.File; + public class UsePoolThreadSample extends GetSample { private static final String LOG_TAG = "UsePoolThreadSample"; @@ -95,12 +96,9 @@ public void run() { } private File getRandomCacheFile() { - File dir = getExternalCacheDir(); - if(dir == null) { - dir = getCacheDir(); - if(dir == null) { - dir = getFilesDir(); - } + File dir = getCacheDir(); + if (dir == null) { + dir = getFilesDir(); } return new File(dir, "sample-" + System.currentTimeMillis() + ".bin"); @@ -108,7 +106,7 @@ private File getRandomCacheFile() { private void saveBytesOnDisk(File destination, byte[] bytes) { // TODO: Spin your own implementation to save the bytes on disk/SD card. - if(bytes != null && destination != null) { + if (bytes != null && destination != null) { Log.d(LOG_TAG, "Saved " + bytes.length + " bytes into file: " + destination.getAbsolutePath()); } } From 08dc9221f0e8785ed767f443a16fa59835bced1c Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sun, 21 Dec 2014 14:51:09 +0100 Subject: [PATCH 027/167] Manually merged PR, Closing #759 --- .../java/com/loopj/android/http/AsyncHttpClient.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index e0222ac95..26103183f 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1190,6 +1190,18 @@ public RequestHandle delete(Context context, String url, Header[] headers, Respo return sendRequest(httpClient, httpContext, delete, null, responseHandler, context); } + /** + * Perform a HTTP DELETE request. + * + * @param url the URL to send the request to. + * @param params additional DELETE parameters or files to send with the request. + * @param responseHandler the response handler instance that should handle the response. + */ + public void delete(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { + final HttpDelete delete = new HttpDelete(getUrlWithQueryString(isUrlEncodingEnabled, url, params)); + sendRequest(httpClient, httpContext, delete, null, responseHandler, null); + } + /** * Perform a HTTP DELETE request. * From f32c234cc475f3a132ad5e5bf45fec6f6137418d Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sun, 21 Dec 2014 14:54:19 +0100 Subject: [PATCH 028/167] Updated build configuration --- .travis.yml | 2 +- build.gradle | 2 +- library/build.gradle | 2 +- sample/build.gradle | 10 +--------- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87a302508..95e9236b8 100755 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: android jdk: openjdk7 android: components: - - build-tools-21.1.1 + - build-tools-21.1.2 - extra-android-support - extra-android-m2repository - android-21 diff --git a/build.gradle b/build.gradle index dd730d647..35c9970e3 100755 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.14.2' + classpath 'com.android.tools.build:gradle:1.0.0' } } diff --git a/library/build.gradle b/library/build.gradle index 697ae5c07..47d51479b 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' android { compileSdkVersion 21 - buildToolsVersion '21.1.1' + buildToolsVersion '21.1.2' defaultConfig { minSdkVersion 3 diff --git a/sample/build.gradle b/sample/build.gradle index 02bceb6ac..0d326e09e 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,11 +1,3 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:0.14.2' - } -} apply plugin: 'com.android.application' repositories { @@ -17,7 +9,7 @@ repositories { android { compileSdkVersion 21 - buildToolsVersion '21.1.1' + buildToolsVersion '21.1.2' defaultConfig { minSdkVersion 3 From 953100a0b6f8f060f57cca43c5d56726226304e7 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 4 Jan 2015 13:39:54 +0100 Subject: [PATCH 029/167] Show response content type which is not allowed. Plus, keep 4-spaces indentation correct. --- .../http/BinaryHttpResponseHandler.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index 3b844dfc5..539a263fa 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -105,13 +105,13 @@ public final void sendResponseMessage(HttpResponse response) throws IOException if (contentTypeHeaders.length != 1) { //malformed/ambiguous HTTP Header, ABORT! sendFailureMessage( + status.getStatusCode(), + response.getAllHeaders(), + null, + new HttpResponseException( status.getStatusCode(), - response.getAllHeaders(), - null, - new HttpResponseException( - status.getStatusCode(), - "None, or more than one, Content-Type Header found!" - ) + "None, or more than one, Content-Type Header found!" + ) ); return; } @@ -129,13 +129,13 @@ public final void sendResponseMessage(HttpResponse response) throws IOException if (!foundAllowedContentType) { //Content-Type not in allowed list, ABORT! sendFailureMessage( + status.getStatusCode(), + response.getAllHeaders(), + null, + new HttpResponseException( status.getStatusCode(), - response.getAllHeaders(), - null, - new HttpResponseException( - status.getStatusCode(), - "Content-Type not allowed!" - ) + "Content-Type (" + contentTypeHeader.getValue() + ") not allowed!" + ) ); return; } From fc479c71f74a275d2eb22dbec2c177f972ed46c6 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 4 Jan 2015 14:20:07 +0100 Subject: [PATCH 030/167] Introduce getURI(String) method to convert a String to a URI. This is particularly useful in situations where the original URL contains special characters that must be retained, for example a '+' sign, and not converted to its encoded form ('%20', in case of '+'). --- .../loopj/android/http/AsyncHttpClient.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 26103183f..bee662e38 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -954,7 +954,7 @@ public RequestHandle post(Context context, String url, RequestParams params, Res * @return RequestHandle of future request process */ public RequestHandle post(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPost(URI.create(url).normalize()), entity), contentType, responseHandler, context); + return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPost(getURI(url)), entity), contentType, responseHandler, context); } /** @@ -972,7 +972,7 @@ public RequestHandle post(Context context, String url, HttpEntity entity, String */ public RequestHandle post(Context context, String url, Header[] headers, RequestParams params, String contentType, ResponseHandlerInterface responseHandler) { - HttpEntityEnclosingRequestBase request = new HttpPost(URI.create(url).normalize()); + HttpEntityEnclosingRequestBase request = new HttpPost(getURI(url)); if (params != null) request.setEntity(paramsToEntity(params, responseHandler)); if (headers != null) request.setHeaders(headers); return sendRequest(httpClient, httpContext, request, contentType, @@ -996,7 +996,7 @@ public RequestHandle post(Context context, String url, Header[] headers, Request */ public RequestHandle post(Context context, String url, Header[] headers, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPost(URI.create(url).normalize()), entity); + HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPost(getURI(url)), entity); if (headers != null) request.setHeaders(headers); return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); } @@ -1055,7 +1055,7 @@ public RequestHandle put(Context context, String url, RequestParams params, Resp * @return RequestHandle of future request process */ public RequestHandle put(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPut(URI.create(url).normalize()), entity), contentType, responseHandler, context); + return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPut(getURI(url)), entity), contentType, responseHandler, context); } /** @@ -1074,7 +1074,7 @@ public RequestHandle put(Context context, String url, HttpEntity entity, String * @return RequestHandle of future request process */ public RequestHandle put(Context context, String url, Header[] headers, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPut(URI.create(url).normalize()), entity); + HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPut(getURI(url)), entity); if (headers != null) request.setHeaders(headers); return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); } @@ -1124,7 +1124,7 @@ public RequestHandle patch(Context context, String url, RequestParams params, Re * @return RequestHandle of future request process */ public RequestHandle patch(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity), contentType, responseHandler, context); + return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpPatch(getURI(url)), entity), contentType, responseHandler, context); } /** @@ -1143,7 +1143,7 @@ public RequestHandle patch(Context context, String url, HttpEntity entity, Strin * @return RequestHandle of future request process */ public RequestHandle patch(Context context, String url, Header[] headers, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { - HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPatch(URI.create(url).normalize()), entity); + HttpEntityEnclosingRequestBase request = addEntityToRequestBase(new HttpPatch(getURI(url)), entity); if (headers != null) request.setHeaders(headers); return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context); } @@ -1171,7 +1171,7 @@ public RequestHandle delete(String url, ResponseHandlerInterface responseHandler * @return RequestHandle of future request process */ public RequestHandle delete(Context context, String url, ResponseHandlerInterface responseHandler) { - final HttpDelete delete = new HttpDelete(URI.create(url).normalize()); + final HttpDelete delete = new HttpDelete(getURI(url)); return sendRequest(httpClient, httpContext, delete, null, responseHandler, context); } @@ -1185,7 +1185,7 @@ public RequestHandle delete(Context context, String url, ResponseHandlerInterfac * @return RequestHandle of future request process */ public RequestHandle delete(Context context, String url, Header[] headers, ResponseHandlerInterface responseHandler) { - final HttpDelete delete = new HttpDelete(URI.create(url).normalize()); + final HttpDelete delete = new HttpDelete(getURI(url)); if (headers != null) delete.setHeaders(headers); return sendRequest(httpClient, httpContext, delete, null, responseHandler, context); } @@ -1299,6 +1299,16 @@ protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpCo return requestHandle; } + /** + * Returns a {@link URI} instance for the specified, absolute URL string. + * + * @param url absolute URL string, containing scheme, host and path + * @return URI instance for the URL string + */ + protected URI getURI(String url) { + return URI.create(url).normalize(); + } + /** * Sets state of URL encoding feature, see bug #227, this method allows you to turn off and on * this auto-magic feature on-demand. From d7d7e81625371d98fb3df003afe26813f1a1641b Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 4 Jan 2015 18:54:56 +0100 Subject: [PATCH 031/167] Couple of fixes, one is very important: 1) When uploading many requests using JSON streamer, the reusable StringBuffer would have been emptied; a fix is no w enclosed 2) Added a feature request: Let the user decide whether to embed "_elapsed" field, and even customize its name, or disable it completely. --- .../android/http/JsonStreamerEntity.java | 159 ++++++++++-------- .../com/loopj/android/http/RequestParams.java | 28 ++- 2 files changed, 108 insertions(+), 79 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index 0df47d477..4507cc43a 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -18,6 +18,7 @@ package com.loopj.android.http; +import android.text.TextUtils; import android.util.Log; import org.apache.http.Header; @@ -51,11 +52,6 @@ public class JsonStreamerEntity implements HttpEntity { // Buffer used for reading from input streams. private final byte[] buffer = new byte[BUFFER_SIZE]; - // Reusable StringBuilder used by escape() method. - // Its size is just initial, if more space is needed, the system will - // automatically enlarge the buffer. - private static final StringBuilder BUILDER = new StringBuilder(128); - private static final byte[] JSON_TRUE = "true".getBytes(); private static final byte[] JSON_FALSE = "false".getBytes(); private static final byte[] JSON_NULL = "null".getBytes(); @@ -80,11 +76,14 @@ public class JsonStreamerEntity implements HttpEntity { // Whether to use gzip compression while uploading private final Header contentEncoding; + private final String elapsedField; + private final ResponseHandlerInterface progressHandler; - public JsonStreamerEntity(ResponseHandlerInterface progressHandler, boolean useGZipCompression) { + public JsonStreamerEntity(ResponseHandlerInterface progressHandler, boolean useGZipCompression, String elapsedField) { this.progressHandler = progressHandler; this.contentEncoding = useGZipCompression ? HEADER_GZIP_ENCODING : null; + this.elapsedField = elapsedField; } /** @@ -157,69 +156,86 @@ public void writeTo(final OutputStream out) throws IOException { // Keys used by the HashMaps. Set keys = jsonParams.keySet(); + int keysCount = keys.size(); + int keysProcessed = -1; boolean isFileWrapper; // Go over all keys and handle each's value. for (String key : keys) { - // Evaluate the value (which cannot be null). - Object value = jsonParams.get(key); + // Indicate that this key has been processed. + keysProcessed++; - // Bail out prematurely if value's null. - if (value == null) { - continue; - } + try { + // Evaluate the value (which cannot be null). + Object value = jsonParams.get(key); - // Write the JSON object's key. - os.write(escape(key)); - os.write(':'); + // Bail out prematurely if value's null. + if (value == null) { + continue; + } + + // Write the JSON object's key. + os.write(escape(key)); + os.write(':'); - // Check if this is a FileWrapper. - isFileWrapper = value instanceof RequestParams.FileWrapper; + // Check if this is a FileWrapper. + isFileWrapper = value instanceof RequestParams.FileWrapper; - // If a file should be uploaded. - if (isFileWrapper || value instanceof RequestParams.StreamWrapper) { - // All uploads are sent as an object containing the file's details. - os.write('{'); + // If a file should be uploaded. + if (isFileWrapper || value instanceof RequestParams.StreamWrapper) { + // All uploads are sent as an object containing the file's details. + os.write('{'); - // Determine how to handle this entry. - if (isFileWrapper) { - writeToFromFile(os, (RequestParams.FileWrapper) value); + // Determine how to handle this entry. + if (isFileWrapper) { + writeToFromFile(os, (RequestParams.FileWrapper) value); + } else { + writeToFromStream(os, (RequestParams.StreamWrapper) value); + } + + // End the file's object and prepare for next one. + os.write('}'); + } else if (value instanceof JsonValueInterface) { + os.write(((JsonValueInterface) value).getEscapedJsonValue()); + } else if (value instanceof org.json.JSONObject) { + os.write(((org.json.JSONObject) value).toString().getBytes()); + } else if (value instanceof org.json.JSONArray) { + os.write(((org.json.JSONArray) value).toString().getBytes()); + } else if (value instanceof Boolean) { + os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); + } else if (value instanceof Long) { + os.write((((Number) value).longValue() + "").getBytes()); + } else if (value instanceof Double) { + os.write((((Number) value).doubleValue() + "").getBytes()); + } else if (value instanceof Float) { + os.write((((Number) value).floatValue() + "").getBytes()); + } else if (value instanceof Integer) { + os.write((((Number) value).intValue() + "").getBytes()); } else { - writeToFromStream(os, (RequestParams.StreamWrapper) value); + os.write(escape(value.toString())); + } + } finally { + // Separate each K:V with a comma, except the last one. + if (!TextUtils.isEmpty(elapsedField) || keysProcessed < keysCount) { + os.write(','); } - - // End the file's object and prepare for next one. - os.write('}'); - } else if (value instanceof JsonValueInterface) { - os.write(((JsonValueInterface) value).getEscapedJsonValue()); - } else if (value instanceof org.json.JSONObject) { - os.write(((org.json.JSONObject) value).toString().getBytes()); - } else if (value instanceof org.json.JSONArray) { - os.write(((org.json.JSONArray) value).toString().getBytes()); - } else if (value instanceof Boolean) { - os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); - } else if (value instanceof Long) { - os.write((((Number) value).longValue() + "").getBytes()); - } else if (value instanceof Double) { - os.write((((Number) value).doubleValue() + "").getBytes()); - } else if (value instanceof Float) { - os.write((((Number) value).floatValue() + "").getBytes()); - } else if (value instanceof Integer) { - os.write((((Number) value).intValue() + "").getBytes()); - } else { - os.write(escape(value.toString())); } - - os.write(','); } + // Calculate how many milliseconds it took to upload the contents. + long elapsedTime = System.currentTimeMillis() - now; + // Include the elapsed time taken to upload everything. // This might be useful for somebody, but it serves us well since // there will almost always be a ',' as the last sent character. - os.write(STREAM_ELAPSED); - os.write(':'); - long elapsedTime = System.currentTimeMillis() - now; - os.write((elapsedTime + "}").getBytes()); + if (!TextUtils.isEmpty(elapsedField)) { + os.write(STREAM_ELAPSED); + os.write(':'); + os.write((elapsedTime + "").getBytes()); + } + + // Close the JSON object. + os.write('}'); Log.i(LOG_TAG, "Uploaded JSON in " + Math.floor(elapsedTime / 1000) + " seconds"); @@ -321,60 +337,57 @@ static byte[] escape(String string) { return JSON_NULL; } + // Create a string builder to generate the escaped string. + StringBuilder sb = new StringBuilder(128); + // Surround with quotations. - BUILDER.append('"'); + sb.append('"'); int length = string.length(), pos = -1; while (++pos < length) { char ch = string.charAt(pos); switch (ch) { case '"': - BUILDER.append("\\\""); + sb.append("\\\""); break; case '\\': - BUILDER.append("\\\\"); + sb.append("\\\\"); break; case '\b': - BUILDER.append("\\b"); + sb.append("\\b"); break; case '\f': - BUILDER.append("\\f"); + sb.append("\\f"); break; case '\n': - BUILDER.append("\\n"); + sb.append("\\n"); break; case '\r': - BUILDER.append("\\r"); + sb.append("\\r"); break; case '\t': - BUILDER.append("\\t"); + sb.append("\\t"); break; default: // Reference: http://www.unicode.org/versions/Unicode5.1.0/ if ((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) { String intString = Integer.toHexString(ch); - BUILDER.append("\\u"); + sb.append("\\u"); int intLength = 4 - intString.length(); for (int zero = 0; zero < intLength; zero++) { - BUILDER.append('0'); + sb.append('0'); } - BUILDER.append(intString.toUpperCase(Locale.US)); + sb.append(intString.toUpperCase(Locale.US)); } else { - BUILDER.append(ch); + sb.append(ch); } break; } } // Surround with quotations. - BUILDER.append('"'); - - try { - return BUILDER.toString().getBytes(); - } finally { - // Empty the String buffer. - // This is 20-30% faster than instantiating a new object. - BUILDER.setLength(0); - } + sb.append('"'); + + return sb.toString().getBytes(); } } diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 28a7a93a4..4c4ce49e5 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -99,6 +99,7 @@ public class RequestParams implements Serializable { protected final static String LOG_TAG = "RequestParams"; protected boolean isRepeatable; protected boolean useJsonStreamer; + protected String elapsedFieldInJsonStreamer = "_elapsed"; protected boolean autoCloseInputStreams; protected final ConcurrentHashMap urlParams = new ConcurrentHashMap(); protected final ConcurrentHashMap streamParams = new ConcurrentHashMap(); @@ -412,12 +413,25 @@ public String toString() { return result.toString(); } - public void setHttpEntityIsRepeatable(boolean isRepeatable) { - this.isRepeatable = isRepeatable; + public void setHttpEntityIsRepeatable(boolean flag) { + this.isRepeatable = flag; } - public void setUseJsonStreamer(boolean useJsonStreamer) { - this.useJsonStreamer = useJsonStreamer; + public void setUseJsonStreamer(boolean flag) { + this.useJsonStreamer = flag; + } + + /** + * Sets an additional field when upload a JSON object through the streamer + * to hold the time, in milliseconds, it took to upload the payload. By + * default, this field is set to "_elapsed". + * + * To disable this feature, call this method with null as the field value. + * + * @param value field name to add elapsed time, or null to disable + */ + public void setElapsedFieldInJsonStreamer(String value) { + this.elapsedFieldInJsonStreamer = value; } /** @@ -449,8 +463,10 @@ public HttpEntity getEntity(ResponseHandlerInterface progressHandler) throws IOE } private HttpEntity createJsonStreamerEntity(ResponseHandlerInterface progressHandler) throws IOException { - JsonStreamerEntity entity = new JsonStreamerEntity(progressHandler, - !fileParams.isEmpty() || !streamParams.isEmpty()); + JsonStreamerEntity entity = new JsonStreamerEntity( + progressHandler, + !fileParams.isEmpty() || !streamParams.isEmpty(), + elapsedFieldInJsonStreamer); // Add string params for (ConcurrentHashMap.Entry entry : urlParams.entrySet()) { From 7e5d89a841776c22373aa3508158fcd27c84c9d0 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 4 Jan 2015 18:59:16 +0100 Subject: [PATCH 032/167] Forgot to use the new field name :) --- .../loopj/android/http/JsonStreamerEntity.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index 4507cc43a..920ec8e43 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -58,7 +58,6 @@ public class JsonStreamerEntity implements HttpEntity { private static final byte[] STREAM_NAME = escape("name"); private static final byte[] STREAM_TYPE = escape("type"); private static final byte[] STREAM_CONTENTS = escape("contents"); - private static final byte[] STREAM_ELAPSED = escape("_elapsed"); private static final Header HEADER_JSON_CONTENT = new BasicHeader( @@ -76,14 +75,16 @@ public class JsonStreamerEntity implements HttpEntity { // Whether to use gzip compression while uploading private final Header contentEncoding; - private final String elapsedField; + private final byte[] elapsedField; private final ResponseHandlerInterface progressHandler; public JsonStreamerEntity(ResponseHandlerInterface progressHandler, boolean useGZipCompression, String elapsedField) { this.progressHandler = progressHandler; this.contentEncoding = useGZipCompression ? HEADER_GZIP_ENCODING : null; - this.elapsedField = elapsedField; + this.elapsedField = TextUtils.isEmpty(elapsedField) + ? null + : escape(elapsedField); } /** @@ -146,7 +147,7 @@ public void writeTo(final OutputStream out) throws IOException { // Use GZIP compression when sending streams, otherwise just use // a buffered output stream to speed things up a bit. - OutputStream os = null != contentEncoding + OutputStream os = contentEncoding != null ? new GZIPOutputStream(out, BUFFER_SIZE) : out; @@ -216,7 +217,7 @@ public void writeTo(final OutputStream out) throws IOException { } } finally { // Separate each K:V with a comma, except the last one. - if (!TextUtils.isEmpty(elapsedField) || keysProcessed < keysCount) { + if (elapsedField != null || keysProcessed < keysCount) { os.write(','); } } @@ -228,8 +229,8 @@ public void writeTo(final OutputStream out) throws IOException { // Include the elapsed time taken to upload everything. // This might be useful for somebody, but it serves us well since // there will almost always be a ',' as the last sent character. - if (!TextUtils.isEmpty(elapsedField)) { - os.write(STREAM_ELAPSED); + if (elapsedField != null) { + os.write(elapsedField); os.write(':'); os.write((elapsedTime + "").getBytes()); } From eff7671daa251c024823fa58699ae7c7554b9be1 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 4 Jan 2015 19:07:51 +0100 Subject: [PATCH 033/167] Fixed a small bug when a value is null. --- .../android/http/JsonStreamerEntity.java | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index 920ec8e43..fa319551d 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -170,50 +170,50 @@ public void writeTo(final OutputStream out) throws IOException { // Evaluate the value (which cannot be null). Object value = jsonParams.get(key); - // Bail out prematurely if value's null. - if (value == null) { - continue; - } - // Write the JSON object's key. os.write(escape(key)); os.write(':'); - // Check if this is a FileWrapper. - isFileWrapper = value instanceof RequestParams.FileWrapper; - - // If a file should be uploaded. - if (isFileWrapper || value instanceof RequestParams.StreamWrapper) { - // All uploads are sent as an object containing the file's details. - os.write('{'); + // Bail out prematurely if value's null. + if (value == null) { + os.write(JSON_NULL); + } else { + // Check if this is a FileWrapper. + isFileWrapper = value instanceof RequestParams.FileWrapper; + + // If a file should be uploaded. + if (isFileWrapper || value instanceof RequestParams.StreamWrapper) { + // All uploads are sent as an object containing the file's details. + os.write('{'); + + // Determine how to handle this entry. + if (isFileWrapper) { + writeToFromFile(os, (RequestParams.FileWrapper) value); + } else { + writeToFromStream(os, (RequestParams.StreamWrapper) value); + } - // Determine how to handle this entry. - if (isFileWrapper) { - writeToFromFile(os, (RequestParams.FileWrapper) value); + // End the file's object and prepare for next one. + os.write('}'); + } else if (value instanceof JsonValueInterface) { + os.write(((JsonValueInterface) value).getEscapedJsonValue()); + } else if (value instanceof org.json.JSONObject) { + os.write(((org.json.JSONObject) value).toString().getBytes()); + } else if (value instanceof org.json.JSONArray) { + os.write(((org.json.JSONArray) value).toString().getBytes()); + } else if (value instanceof Boolean) { + os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); + } else if (value instanceof Long) { + os.write((((Number) value).longValue() + "").getBytes()); + } else if (value instanceof Double) { + os.write((((Number) value).doubleValue() + "").getBytes()); + } else if (value instanceof Float) { + os.write((((Number) value).floatValue() + "").getBytes()); + } else if (value instanceof Integer) { + os.write((((Number) value).intValue() + "").getBytes()); } else { - writeToFromStream(os, (RequestParams.StreamWrapper) value); + os.write(escape(value.toString())); } - - // End the file's object and prepare for next one. - os.write('}'); - } else if (value instanceof JsonValueInterface) { - os.write(((JsonValueInterface) value).getEscapedJsonValue()); - } else if (value instanceof org.json.JSONObject) { - os.write(((org.json.JSONObject) value).toString().getBytes()); - } else if (value instanceof org.json.JSONArray) { - os.write(((org.json.JSONArray) value).toString().getBytes()); - } else if (value instanceof Boolean) { - os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); - } else if (value instanceof Long) { - os.write((((Number) value).longValue() + "").getBytes()); - } else if (value instanceof Double) { - os.write((((Number) value).doubleValue() + "").getBytes()); - } else if (value instanceof Float) { - os.write((((Number) value).floatValue() + "").getBytes()); - } else if (value instanceof Integer) { - os.write((((Number) value).intValue() + "").getBytes()); - } else { - os.write(escape(value.toString())); } } finally { // Separate each K:V with a comma, except the last one. From 2b4c33b097bee34eada2f12e369f368b228829e9 Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Sun, 4 Jan 2015 19:17:47 +0100 Subject: [PATCH 034/167] Fixed a last bug when counting number of processed keys. The pull is now fully tested and can be incorporated. --- .../android/http/JsonStreamerEntity.java | 142 +++++++++--------- 1 file changed, 72 insertions(+), 70 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index fa319551d..aea2d1d14 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -158,88 +158,90 @@ public void writeTo(final OutputStream out) throws IOException { Set keys = jsonParams.keySet(); int keysCount = keys.size(); - int keysProcessed = -1; - boolean isFileWrapper; - - // Go over all keys and handle each's value. - for (String key : keys) { - // Indicate that this key has been processed. - keysProcessed++; - - try { - // Evaluate the value (which cannot be null). - Object value = jsonParams.get(key); - - // Write the JSON object's key. - os.write(escape(key)); - os.write(':'); - - // Bail out prematurely if value's null. - if (value == null) { - os.write(JSON_NULL); - } else { - // Check if this is a FileWrapper. - isFileWrapper = value instanceof RequestParams.FileWrapper; - - // If a file should be uploaded. - if (isFileWrapper || value instanceof RequestParams.StreamWrapper) { - // All uploads are sent as an object containing the file's details. - os.write('{'); - - // Determine how to handle this entry. - if (isFileWrapper) { - writeToFromFile(os, (RequestParams.FileWrapper) value); + if (0 < keysCount) { + int keysProcessed = 0; + boolean isFileWrapper; + + // Go over all keys and handle each's value. + for (String key : keys) { + // Indicate that this key has been processed. + keysProcessed++; + + try { + // Evaluate the value (which cannot be null). + Object value = jsonParams.get(key); + + // Write the JSON object's key. + os.write(escape(key)); + os.write(':'); + + // Bail out prematurely if value's null. + if (value == null) { + os.write(JSON_NULL); + } else { + // Check if this is a FileWrapper. + isFileWrapper = value instanceof RequestParams.FileWrapper; + + // If a file should be uploaded. + if (isFileWrapper || value instanceof RequestParams.StreamWrapper) { + // All uploads are sent as an object containing the file's details. + os.write('{'); + + // Determine how to handle this entry. + if (isFileWrapper) { + writeToFromFile(os, (RequestParams.FileWrapper) value); + } else { + writeToFromStream(os, (RequestParams.StreamWrapper) value); + } + + // End the file's object and prepare for next one. + os.write('}'); + } else if (value instanceof JsonValueInterface) { + os.write(((JsonValueInterface) value).getEscapedJsonValue()); + } else if (value instanceof org.json.JSONObject) { + os.write(((org.json.JSONObject) value).toString().getBytes()); + } else if (value instanceof org.json.JSONArray) { + os.write(((org.json.JSONArray) value).toString().getBytes()); + } else if (value instanceof Boolean) { + os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); + } else if (value instanceof Long) { + os.write((((Number) value).longValue() + "").getBytes()); + } else if (value instanceof Double) { + os.write((((Number) value).doubleValue() + "").getBytes()); + } else if (value instanceof Float) { + os.write((((Number) value).floatValue() + "").getBytes()); + } else if (value instanceof Integer) { + os.write((((Number) value).intValue() + "").getBytes()); } else { - writeToFromStream(os, (RequestParams.StreamWrapper) value); + os.write(escape(value.toString())); } - - // End the file's object and prepare for next one. - os.write('}'); - } else if (value instanceof JsonValueInterface) { - os.write(((JsonValueInterface) value).getEscapedJsonValue()); - } else if (value instanceof org.json.JSONObject) { - os.write(((org.json.JSONObject) value).toString().getBytes()); - } else if (value instanceof org.json.JSONArray) { - os.write(((org.json.JSONArray) value).toString().getBytes()); - } else if (value instanceof Boolean) { - os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); - } else if (value instanceof Long) { - os.write((((Number) value).longValue() + "").getBytes()); - } else if (value instanceof Double) { - os.write((((Number) value).doubleValue() + "").getBytes()); - } else if (value instanceof Float) { - os.write((((Number) value).floatValue() + "").getBytes()); - } else if (value instanceof Integer) { - os.write((((Number) value).intValue() + "").getBytes()); - } else { - os.write(escape(value.toString())); } - } - } finally { - // Separate each K:V with a comma, except the last one. - if (elapsedField != null || keysProcessed < keysCount) { - os.write(','); + } finally { + // Separate each K:V with a comma, except the last one. + if (elapsedField != null || keysProcessed < keysCount) { + os.write(','); + } } } - } - // Calculate how many milliseconds it took to upload the contents. - long elapsedTime = System.currentTimeMillis() - now; + // Calculate how many milliseconds it took to upload the contents. + long elapsedTime = System.currentTimeMillis() - now; - // Include the elapsed time taken to upload everything. - // This might be useful for somebody, but it serves us well since - // there will almost always be a ',' as the last sent character. - if (elapsedField != null) { - os.write(elapsedField); - os.write(':'); - os.write((elapsedTime + "").getBytes()); + // Include the elapsed time taken to upload everything. + // This might be useful for somebody, but it serves us well since + // there will almost always be a ',' as the last sent character. + if (elapsedField != null) { + os.write(elapsedField); + os.write(':'); + os.write((elapsedTime + "").getBytes()); + } + + Log.i(LOG_TAG, "Uploaded JSON in " + Math.floor(elapsedTime / 1000) + " seconds"); } // Close the JSON object. os.write('}'); - Log.i(LOG_TAG, "Uploaded JSON in " + Math.floor(elapsedTime / 1000) + " seconds"); - // Flush the contents up the stream. os.flush(); AsyncHttpClient.silentCloseOutputStream(os); From cb06265960d63e7e61d5c352d40a6e0ca838066f Mon Sep 17 00:00:00 2001 From: Noor Dawod Date: Wed, 21 Jan 2015 21:54:25 +0100 Subject: [PATCH 035/167] Define a new method to catch user-space exceptions and report them. --- .../http/AsyncHttpResponseHandler.java | 99 ++++++++++--------- 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index a61d456e7..aa4c454bb 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -307,6 +307,11 @@ public void onCancel() { Log.d(LOG_TAG, "Request got cancelled"); } + public void onUserException(Throwable error) { + Log.e(LOG_TAG, "User-space exception detected!", error); + throw new RuntimeException(error); + } + @Override final public void sendProgressMessage(int bytesWritten, int bytesTotal) { sendMessage(obtainMessage(PROGRESS_MESSAGE, new Object[]{bytesWritten, bytesTotal})); @@ -346,52 +351,56 @@ final public void sendCancelMessage() { protected void handleMessage(Message message) { Object[] response; - switch (message.what) { - case SUCCESS_MESSAGE: - response = (Object[]) message.obj; - if (response != null && response.length >= 3) { - onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]); - } else { - Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params"); - } - break; - case FAILURE_MESSAGE: - response = (Object[]) message.obj; - if (response != null && response.length >= 4) { - onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]); - } else { - Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params"); - } - break; - case START_MESSAGE: - onStart(); - break; - case FINISH_MESSAGE: - onFinish(); - break; - case PROGRESS_MESSAGE: - response = (Object[]) message.obj; - if (response != null && response.length >= 2) { - try { - onProgress((Integer) response[0], (Integer) response[1]); - } catch (Throwable t) { - Log.e(LOG_TAG, "custom onProgress contains an error", t); + try { + switch (message.what) { + case SUCCESS_MESSAGE: + response = (Object[]) message.obj; + if (response != null && response.length >= 3) { + onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]); + } else { + Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params"); } - } else { - Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params"); - } - break; - case RETRY_MESSAGE: - response = (Object[]) message.obj; - if (response != null && response.length == 1) { - onRetry((Integer) response[0]); - } else { - Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params"); - } - break; - case CANCEL_MESSAGE: - onCancel(); - break; + break; + case FAILURE_MESSAGE: + response = (Object[]) message.obj; + if (response != null && response.length >= 4) { + onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]); + } else { + Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params"); + } + break; + case START_MESSAGE: + onStart(); + break; + case FINISH_MESSAGE: + onFinish(); + break; + case PROGRESS_MESSAGE: + response = (Object[]) message.obj; + if (response != null && response.length >= 2) { + try { + onProgress((Integer) response[0], (Integer) response[1]); + } catch (Throwable t) { + Log.e(LOG_TAG, "custom onProgress contains an error", t); + } + } else { + Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params"); + } + break; + case RETRY_MESSAGE: + response = (Object[]) message.obj; + if (response != null && response.length == 1) { + onRetry((Integer) response[0]); + } else { + Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params"); + } + break; + case CANCEL_MESSAGE: + onCancel(); + break; + } + } catch(Throwable error) { + onUserException(error); } } From 18eece129eb7b31c59ee26795c194e52f9093012 Mon Sep 17 00:00:00 2001 From: Felixledref Date: Thu, 22 Jan 2015 17:51:32 +0100 Subject: [PATCH 036/167] updated JsonHttpResponseHandler.java to handle string, numeric, boolean and null value --- gradle/wrapper/gradle-wrapper.properties | 4 +-- .../android/http/JsonHttpResponseHandler.java | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 27a8a50e9..5a5b38e62 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jul 02 18:01:59 CEST 2014 +#Thu Jan 22 17:47:44 CET 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index 52663a072..b39919968 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -122,16 +122,17 @@ public void run() { postRunnable(new Runnable() { @Override public void run() { - if (jsonResponse instanceof JSONObject) { + if(jsonResponse == null){ + onSuccess(statusCode, headers, (String) jsonResponse); + }else if (jsonResponse instanceof JSONObject) { onSuccess(statusCode, headers, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { onSuccess(statusCode, headers, (JSONArray) jsonResponse); } else if (jsonResponse instanceof String) { - onFailure(statusCode, headers, (String) jsonResponse, new JSONException("Response cannot be parsed as JSON data")); + onSuccess(statusCode, headers, (String) jsonResponse); } else { onFailure(statusCode, headers, new JSONException("Unexpected response type " + jsonResponse.getClass().getName()), (JSONObject) null); } - } }); } catch (final JSONException ex) { @@ -166,7 +167,9 @@ public void run() { postRunnable(new Runnable() { @Override public void run() { - if (jsonResponse instanceof JSONObject) { + if (jsonResponse == null){ + onFailure(statusCode, headers, (String) jsonResponse, throwable); + }else if (jsonResponse instanceof JSONObject) { onFailure(statusCode, headers, throwable, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { onFailure(statusCode, headers, throwable, (JSONArray) jsonResponse); @@ -220,13 +223,20 @@ protected Object parseResponse(byte[] responseBody) throws JSONException { if (jsonString.startsWith(UTF8_BOM)) { jsonString = jsonString.substring(1); } - if (jsonString.startsWith("{") || jsonString.startsWith("[")) { + // Check if the string is an JSONObject style {} or JSONArray style [] + // If not we consider this as a string + if (( jsonString.startsWith("{") && jsonString.endsWith("}") ) + || jsonString.startsWith("[") && jsonString.endsWith("]") ) { result = new JSONTokener(jsonString).nextValue(); + return result; + } + // Check if this is a String "my String value" and remove quote + // Other value type (numerical, boolean) should be without quote + else if ( jsonString.startsWith("\"") && jsonString.endsWith("\"") ){ + result = jsonString.substring(1,jsonString.length()-1); + return result; } } - if (result == null) { - result = jsonString; - } - return result; + return jsonString; } } From 840828cc2f4de0a242626a94d82c4c08af86ca97 Mon Sep 17 00:00:00 2001 From: Felixledref Date: Fri, 23 Jan 2015 16:43:16 +0100 Subject: [PATCH 037/167] updated JsonHttpResponseHandler.java with a boolean which handle RFC5179 or latest --- .../android/http/JsonHttpResponseHandler.java | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index b39919968..6688bcccc 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -39,6 +39,9 @@ public class JsonHttpResponseHandler extends TextHttpResponseHandler { private static final String LOG_TAG = "JsonHttpResponseHandler"; + + private boolean useRFC5179CompatibilityMode = true; + /** * Creates new JsonHttpResponseHandler, with JSON String encoding UTF-8 */ @@ -47,7 +50,7 @@ public JsonHttpResponseHandler() { } /** - * Creates new JsonHttpRespnseHandler with given JSON String encoding + * Creates new JsonHttpResponseHandler with given JSON String encoding * * @param encoding String encoding to be used when parsing JSON */ @@ -55,6 +58,27 @@ public JsonHttpResponseHandler(String encoding) { super(encoding); } + /** + * Creates new JsonHttpResponseHandler with JSON String encoding UTF-8 and given RFC5179CompatibilityMode + * + * @param useRFC5179CompatibilityMode Boolean mode to use RFC5179 or latest + */ + public JsonHttpResponseHandler(boolean useRFC5179CompatibilityMode) { + super(DEFAULT_CHARSET); + this.useRFC5179CompatibilityMode = useRFC5179CompatibilityMode; + } + + /** + * Creates new JsonHttpResponseHandler with given JSON String encoding and RFC5179CompatibilityMode + * + * @param encoding String encoding to be used when parsing JSON + * @param useRFC5179CompatibilityMode Boolean mode to use RFC5179 or latest + */ + public JsonHttpResponseHandler(String encoding, boolean useRFC5179CompatibilityMode) { + super(encoding); + this.useRFC5179CompatibilityMode = useRFC5179CompatibilityMode; + } + /** * Returns when request succeeds * @@ -122,14 +146,20 @@ public void run() { postRunnable(new Runnable() { @Override public void run() { - if(jsonResponse == null){ + // In RFC5179 a null value is not a valid JSON + if(!useRFC5179CompatibilityMode && jsonResponse == null){ onSuccess(statusCode, headers, (String) jsonResponse); }else if (jsonResponse instanceof JSONObject) { onSuccess(statusCode, headers, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { onSuccess(statusCode, headers, (JSONArray) jsonResponse); } else if (jsonResponse instanceof String) { - onSuccess(statusCode, headers, (String) jsonResponse); + // In RFC5179 a simple string value is not a valid JSON + if ( useRFC5179CompatibilityMode){ + onFailure(statusCode, headers, (String) jsonResponse, new JSONException("Response cannot be parsed as JSON data")); + }else{ + onSuccess(statusCode, headers, (String) jsonResponse); + } } else { onFailure(statusCode, headers, new JSONException("Unexpected response type " + jsonResponse.getClass().getName()), (JSONObject) null); } @@ -167,7 +197,8 @@ public void run() { postRunnable(new Runnable() { @Override public void run() { - if (jsonResponse == null){ + // In RFC5179 a null value is not a valid JSON + if (!useRFC5179CompatibilityMode && jsonResponse == null){ onFailure(statusCode, headers, (String) jsonResponse, throwable); }else if (jsonResponse instanceof JSONObject) { onFailure(statusCode, headers, throwable, (JSONObject) jsonResponse); @@ -223,20 +254,36 @@ protected Object parseResponse(byte[] responseBody) throws JSONException { if (jsonString.startsWith(UTF8_BOM)) { jsonString = jsonString.substring(1); } - // Check if the string is an JSONObject style {} or JSONArray style [] - // If not we consider this as a string - if (( jsonString.startsWith("{") && jsonString.endsWith("}") ) - || jsonString.startsWith("[") && jsonString.endsWith("]") ) { - result = new JSONTokener(jsonString).nextValue(); - return result; - } - // Check if this is a String "my String value" and remove quote - // Other value type (numerical, boolean) should be without quote - else if ( jsonString.startsWith("\"") && jsonString.endsWith("\"") ){ - result = jsonString.substring(1,jsonString.length()-1); - return result; + if ( useRFC5179CompatibilityMode){ + if (jsonString.startsWith("{") || jsonString.startsWith("[")) { + result = new JSONTokener(jsonString).nextValue(); + } + }else{ + // Check if the string is an JSONObject style {} or JSONArray style [] + // If not we consider this as a string + if (( jsonString.startsWith("{") && jsonString.endsWith("}") ) + || jsonString.startsWith("[") && jsonString.endsWith("]") ) { + result = new JSONTokener(jsonString).nextValue(); + } + // Check if this is a String "my String value" and remove quote + // Other value type (numerical, boolean) should be without quote + else if ( jsonString.startsWith("\"") && jsonString.endsWith("\"") ){ + result = jsonString.substring(1,jsonString.length()-1); + } } } - return jsonString; + if (result == null) { + result = jsonString; + } + return result; + } + + public boolean isUseRFC5179CompatibilityMode() { + return useRFC5179CompatibilityMode; } + + public void setUseRFC5179CompatibilityMode(boolean useRFC5179CompatibilityMode) { + this.useRFC5179CompatibilityMode = useRFC5179CompatibilityMode; + } + } From ce7bb12d56d0ec063175d4aad0d497c1ec6b3da7 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sat, 21 Feb 2015 12:25:16 +0100 Subject: [PATCH 038/167] Build configuration upgrade --- build.gradle | 2 +- sample/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 35c9970e3..cfa2b19b0 100755 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' + classpath 'com.android.tools.build:gradle:1.1.0' } } diff --git a/sample/build.gradle b/sample/build.gradle index 0d326e09e..84507453c 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -26,7 +26,7 @@ android { warningsAsErrors true quiet false showAll true - disable 'OldTargetApi' + disable 'OldTargetApi', 'LongLogTag' } packagingOptions { From 929a8955bc1922efc19d30244990245bfcc6ed38 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sat, 21 Feb 2015 12:27:13 +0100 Subject: [PATCH 039/167] Fixed Lint issues --- .../java/com/loopj/android/http/AsyncHttpResponseHandler.java | 1 - .../main/java/com/loopj/android/http/JsonStreamerEntity.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index aa4c454bb..f03c1423b 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -425,7 +425,6 @@ protected void postRunnable(Runnable runnable) { runnable.run(); } else { // Otherwise, run on provided handler - Utils.asserts(handler != null, "handler should not be null!"); handler.post(runnable); } } diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index aea2d1d14..b65b42710 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -199,9 +199,9 @@ public void writeTo(final OutputStream out) throws IOException { } else if (value instanceof JsonValueInterface) { os.write(((JsonValueInterface) value).getEscapedJsonValue()); } else if (value instanceof org.json.JSONObject) { - os.write(((org.json.JSONObject) value).toString().getBytes()); + os.write(value.toString().getBytes()); } else if (value instanceof org.json.JSONArray) { - os.write(((org.json.JSONArray) value).toString().getBytes()); + os.write(value.toString().getBytes()); } else if (value instanceof Boolean) { os.write((Boolean) value ? JSON_TRUE : JSON_FALSE); } else if (value instanceof Long) { From fccf6f22e7dd20556c868e420d16b2eb83d9bfbe Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sat, 21 Feb 2015 12:32:18 +0100 Subject: [PATCH 040/167] Code formatting, removed duplicate UTF8_BOM removal code --- .../android/http/JsonHttpResponseHandler.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index 6688bcccc..66ebcdac9 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -71,7 +71,7 @@ public JsonHttpResponseHandler(boolean useRFC5179CompatibilityMode) { /** * Creates new JsonHttpResponseHandler with given JSON String encoding and RFC5179CompatibilityMode * - * @param encoding String encoding to be used when parsing JSON + * @param encoding String encoding to be used when parsing JSON * @param useRFC5179CompatibilityMode Boolean mode to use RFC5179 or latest */ public JsonHttpResponseHandler(String encoding, boolean useRFC5179CompatibilityMode) { @@ -147,17 +147,17 @@ public void run() { @Override public void run() { // In RFC5179 a null value is not a valid JSON - if(!useRFC5179CompatibilityMode && jsonResponse == null){ + if (!useRFC5179CompatibilityMode && jsonResponse == null) { onSuccess(statusCode, headers, (String) jsonResponse); - }else if (jsonResponse instanceof JSONObject) { + } else if (jsonResponse instanceof JSONObject) { onSuccess(statusCode, headers, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { onSuccess(statusCode, headers, (JSONArray) jsonResponse); } else if (jsonResponse instanceof String) { // In RFC5179 a simple string value is not a valid JSON - if ( useRFC5179CompatibilityMode){ + if (useRFC5179CompatibilityMode) { onFailure(statusCode, headers, (String) jsonResponse, new JSONException("Response cannot be parsed as JSON data")); - }else{ + } else { onSuccess(statusCode, headers, (String) jsonResponse); } } else { @@ -198,9 +198,9 @@ public void run() { @Override public void run() { // In RFC5179 a null value is not a valid JSON - if (!useRFC5179CompatibilityMode && jsonResponse == null){ + if (!useRFC5179CompatibilityMode && jsonResponse == null) { onFailure(statusCode, headers, (String) jsonResponse, throwable); - }else if (jsonResponse instanceof JSONObject) { + } else if (jsonResponse instanceof JSONObject) { onFailure(statusCode, headers, throwable, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { onFailure(statusCode, headers, throwable, (JSONArray) jsonResponse); @@ -251,24 +251,21 @@ protected Object parseResponse(byte[] responseBody) throws JSONException { String jsonString = getResponseString(responseBody, getCharset()); if (jsonString != null) { jsonString = jsonString.trim(); - if (jsonString.startsWith(UTF8_BOM)) { - jsonString = jsonString.substring(1); - } - if ( useRFC5179CompatibilityMode){ + if (useRFC5179CompatibilityMode) { if (jsonString.startsWith("{") || jsonString.startsWith("[")) { result = new JSONTokener(jsonString).nextValue(); } - }else{ + } else { // Check if the string is an JSONObject style {} or JSONArray style [] // If not we consider this as a string - if (( jsonString.startsWith("{") && jsonString.endsWith("}") ) - || jsonString.startsWith("[") && jsonString.endsWith("]") ) { + if ((jsonString.startsWith("{") && jsonString.endsWith("}")) + || jsonString.startsWith("[") && jsonString.endsWith("]")) { result = new JSONTokener(jsonString).nextValue(); } // Check if this is a String "my String value" and remove quote // Other value type (numerical, boolean) should be without quote - else if ( jsonString.startsWith("\"") && jsonString.endsWith("\"") ){ - result = jsonString.substring(1,jsonString.length()-1); + else if (jsonString.startsWith("\"") && jsonString.endsWith("\"")) { + result = jsonString.substring(1, jsonString.length() - 1); } } } From 69ec18572d4c58750e778341f76ebeab6618156d Mon Sep 17 00:00:00 2001 From: mareksebera Date: Sat, 21 Feb 2015 12:35:46 +0100 Subject: [PATCH 041/167] LongLogTag ignored for now as temporary solution --- library/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/build.gradle b/library/build.gradle index 47d51479b..d05b0b66e 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -14,7 +14,8 @@ android { warningsAsErrors true quiet false showAll true - disable 'OldTargetApi' + disable 'OldTargetApi', 'LongLogTag' + // TODO: long log tag should be fixed instead of ignored } compileOptions { From 0861aaddf4e54e8b9269b7c091b69e551fc0f32e Mon Sep 17 00:00:00 2001 From: Mark Dresselhaus Date: Wed, 4 Mar 2015 13:51:53 +0100 Subject: [PATCH 042/167] Make SecureSocketFactory verify hostnames closes #816 --- .../android/http/sample/util/SecureSocketFactory.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java index 779c2f0e0..8cc05f43a 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java @@ -45,6 +45,7 @@ import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; @@ -166,7 +167,12 @@ public Socket createSocket(Socket socket, String host, int port, boolean autoClo throws IOException { injectHostname(socket, host); - return sslCtx.getSocketFactory().createSocket(socket, host, port, autoClose); + Socket sslSocket = sslCtx.getSocketFactory().createSocket(socket, host, port, autoClose); + + // throw an exception if the hostname does not match the certificate + getHostnameVerifier().verify(host, (SSLSocket) sslSocket); + + return sslSocket; } @Override From 4a1556af43742621ed3d5c2388db9ddbf8721a6d Mon Sep 17 00:00:00 2001 From: Marc Olzheim Date: Thu, 5 Mar 2015 14:47:47 +0100 Subject: [PATCH 043/167] RequestParams: Use Locale.US for String.format of machine readable strings. --- .../main/java/com/loopj/android/http/RequestParams.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 4c4ce49e5..b4e9ed062 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -38,6 +38,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -567,7 +568,7 @@ private List getParamsList(String key, Object value) { if (nestedKey instanceof String) { Object nestedValue = map.get(nestedKey); if (nestedValue != null) { - params.addAll(getParamsList(key == null ? (String) nestedKey : String.format("%s[%s]", key, nestedKey), + params.addAll(getParamsList(key == null ? (String) nestedKey : String.format(Locale.US, "%s[%s]", key, nestedKey), nestedValue)); } } @@ -576,13 +577,13 @@ private List getParamsList(String key, Object value) { List list = (List) value; int listSize = list.size(); for (int nestedValueIndex = 0; nestedValueIndex < listSize; nestedValueIndex++) { - params.addAll(getParamsList(String.format("%s[%d]", key, nestedValueIndex), list.get(nestedValueIndex))); + params.addAll(getParamsList(String.format(Locale.US, "%s[%d]", key, nestedValueIndex), list.get(nestedValueIndex))); } } else if (value instanceof Object[]) { Object[] array = (Object[]) value; int arrayLength = array.length; for (int nestedValueIndex = 0; nestedValueIndex < arrayLength; nestedValueIndex++) { - params.addAll(getParamsList(String.format("%s[%d]", key, nestedValueIndex), array[nestedValueIndex])); + params.addAll(getParamsList(String.format(Locale.US, "%s[%d]", key, nestedValueIndex), array[nestedValueIndex])); } } else if (value instanceof Set) { Set set = (Set) value; From 4cc5f4fc0b69b30794b20c3ca1dc4bd710a45323 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Thu, 2 Apr 2015 15:03:30 +0200 Subject: [PATCH 044/167] Build target updated to API 22 and Travis CI support updated --- .travis.yml | 4 ++-- library/build.gradle | 6 +++--- sample/build.gradle | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95e9236b8..01d25146e 100755 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,10 @@ language: android jdk: openjdk7 android: components: - - build-tools-21.1.2 + - build-tools-22.0.1 - extra-android-support - extra-android-m2repository - - android-21 + - android-22 licenses: - '.+' script: diff --git a/library/build.gradle b/library/build.gradle index d05b0b66e..6f5a9d3cb 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22.0.1' defaultConfig { minSdkVersion 3 - targetSdkVersion 21 + targetSdkVersion 22 } lintOptions { diff --git a/sample/build.gradle b/sample/build.gradle index 84507453c..370f59ff6 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -8,12 +8,12 @@ repositories { } android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22.0.1' defaultConfig { minSdkVersion 3 - targetSdkVersion 21 + targetSdkVersion 22 } compileOptions { From 945f5e20c9f47995ccb306c4ffd99530f8b7d918 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Thu, 2 Apr 2015 15:10:27 +0200 Subject: [PATCH 045/167] Updated Gradle wrapper --- gradle/wrapper/gradle-wrapper.jar | Bin 51348 -> 52141 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0087cd3b18659b5577cf6ad3ef61f8eb9416ebba..085a1cdc27db1185342f15a00441734e74fe3735 100644 GIT binary patch delta 20006 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 delta 19193 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 ove~tpA@RwG0)=N%#OK!lL%xx2pdXP%h?w Date: Fri, 3 Apr 2015 12:45:08 +0200 Subject: [PATCH 046/167] Added Gradle task installArchives, to install into local Maven repository --- maven_push.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/maven_push.gradle b/maven_push.gradle index 27fff0d8f..93f9f4e05 100755 --- a/maven_push.gradle +++ b/maven_push.gradle @@ -87,6 +87,20 @@ afterEvaluate { project -> } } + task installArchives(type: Upload) { + description "Installs the artifacts to the local Maven repository." + configuration = configurations['archives'] + repositories { + mavenDeployer { + pom.groupId = GROUP + pom.artifactId = POM_ARTIFACT_ID + pom.version = VERSION_NAME + + repository url: "file://${System.properties['user.home']}/.m2/repository" + } + } + } + signing { required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } sign configurations.archives From 24dfe25f92ffb58238fa71b99135fbeb82f7eeee Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 3 Apr 2015 13:29:57 +0200 Subject: [PATCH 047/167] Fixed invalid synchronization impl, Closes #730 --- .../src/main/java/com/loopj/android/http/AsyncHttpClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index ca7955b92..58dd99a81 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1309,9 +1309,10 @@ protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpCo RequestHandle requestHandle = new RequestHandle(request); if (context != null) { + List requestList; // Add request to request map - List requestList = requestMap.get(context); synchronized (requestMap) { + requestList = requestMap.get(context); if (requestList == null) { requestList = Collections.synchronizedList(new LinkedList()); requestMap.put(context, requestList); From 2efb8dbfb9ca3d53dfc5626d5a6a54eb4913ef59 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 3 Apr 2015 13:50:47 +0200 Subject: [PATCH 048/167] UnknownHostException was not caught by whitelist in RetryHandler, Closing #713 --- .../src/main/java/com/loopj/android/http/AsyncHttpRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index 6ae195e23..e18494a43 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -183,7 +183,7 @@ private void makeRequestWithRetries() throws IOException { // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry // (to assist in genuine cases of unknown host) which seems better than outright failure cause = new IOException("UnknownHostException exception: " + e.getMessage()); - retry = (executionCount > 0) && retryHandler.retryRequest(cause, ++executionCount, context); + retry = (executionCount > 0) && retryHandler.retryRequest(e, ++executionCount, context); } catch (NullPointerException e) { // there's a bug in HttpClient 4.0.x that on some occasions causes // DefaultRequestExecutor to throw an NPE, see From e8615d026cc37c260e93d0f175fd91d035b82df7 Mon Sep 17 00:00:00 2001 From: mareksebera Date: Fri, 3 Apr 2015 14:43:12 +0200 Subject: [PATCH 049/167] Allowed to force content-type to be multipart/form-data, Closing #800 --- .../com/loopj/android/http/RequestParams.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index b4e9ed062..1d0e3f4a0 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -99,6 +99,7 @@ public class RequestParams implements Serializable { protected final static String LOG_TAG = "RequestParams"; protected boolean isRepeatable; + protected boolean forceMultipartEntity = false; protected boolean useJsonStreamer; protected String elapsedFieldInJsonStreamer = "_elapsed"; protected boolean autoCloseInputStreams; @@ -122,6 +123,18 @@ public void setContentEncoding(final String encoding) { } } + /** + * If set to true will force Content-Type header to `multipart/form-data` + * even if there are not Files or Streams to be send + * + * Default value is false + * + * @param force boolean, should declare content-type multipart/form-data even without files or streams present + */ + public void setForceMultipartEntityContentType(boolean force) { + this.forceMultipartEntity = force; + } + /** * Constructs a new empty {@code RequestParams} instance. */ @@ -456,7 +469,7 @@ public void setAutoCloseInputStreams(boolean flag) { public HttpEntity getEntity(ResponseHandlerInterface progressHandler) throws IOException { if (useJsonStreamer) { return createJsonStreamerEntity(progressHandler); - } else if (streamParams.isEmpty() && fileParams.isEmpty()) { + } else if (!forceMultipartEntity && streamParams.isEmpty() && fileParams.isEmpty()) { return createFormEntity(); } else { return createMultipartEntity(progressHandler); @@ -465,9 +478,9 @@ public HttpEntity getEntity(ResponseHandlerInterface progressHandler) throws IOE private HttpEntity createJsonStreamerEntity(ResponseHandlerInterface progressHandler) throws IOException { JsonStreamerEntity entity = new JsonStreamerEntity( - progressHandler, - !fileParams.isEmpty() || !streamParams.isEmpty(), - elapsedFieldInJsonStreamer); + progressHandler, + !fileParams.isEmpty() || !streamParams.isEmpty(), + elapsedFieldInJsonStreamer); // Add string params for (ConcurrentHashMap.Entry entry : urlParams.entrySet()) { From e26d72568bfc7c4d2e335e8930c1173e1bc49d62 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 7 Apr 2015 18:12:03 +0800 Subject: [PATCH 050/167] correct typo preemtive to preemptive --- .../loopj/android/http/AsyncHttpClient.java | 24 +++++++++---------- ...eAuthorizationHttpRequestInterceptor.java} | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) rename library/src/main/java/com/loopj/android/http/{PreemtiveAuthorizationHttpRequestInterceptor.java => PreemptiveAuthorizationHttpRequestInterceptor.java} (95%) mode change 100755 => 100644 diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 58dd99a81..7c7fa3036 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -634,10 +634,10 @@ public void setBasicAuth(String username, String password) { * * @param username Basic Auth username * @param password Basic Auth password - * @param preemtive sets authorization in preemtive manner + * @param preemptive sets authorization in preemptive manner */ - public void setBasicAuth(String username, String password, boolean preemtive) { - setBasicAuth(username, password, null, preemtive); + public void setBasicAuth(String username, String password, boolean preemptive) { + setBasicAuth(username, password, null, preemptive); } /** @@ -659,12 +659,12 @@ public void setBasicAuth(String username, String password, AuthScope scope) { * @param username Basic Auth username * @param password Basic Auth password * @param scope an AuthScope object - * @param preemtive sets authorization in preemtive manner + * @param preemptive sets authorization in preemptive manner */ - public void setBasicAuth(String username, String password, AuthScope scope, boolean preemtive) { + public void setBasicAuth(String username, String password, AuthScope scope, boolean preemptive) { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password); setCredentials(scope, credentials); - setAuthenticationPreemptive(preemtive); + setAuthenticationPreemptive(preemptive); } public void setCredentials(AuthScope authScope, Credentials credentials) { @@ -676,16 +676,16 @@ public void setCredentials(AuthScope authScope, Credentials credentials) { } /** - * Sets HttpRequestInterceptor which handles authorization in preemtive way, as workaround you + * Sets HttpRequestInterceptor which handles authorization in preemptive way, as workaround you * can use call `AsyncHttpClient.addHeader("Authorization","Basic base64OfUsernameAndPassword==")` * - * @param isPreemtive whether the authorization is processed in preemtive way + * @param isPreemptive whether the authorization is processed in preemptive way */ - public void setAuthenticationPreemptive(boolean isPreemtive) { - if (isPreemtive) { - httpClient.addRequestInterceptor(new PreemtiveAuthorizationHttpRequestInterceptor(), 0); + public void setAuthenticationPreemptive(boolean isPreemptive) { + if (isPreemptive) { + httpClient.addRequestInterceptor(new PreemptiveAuthorizationHttpRequestInterceptor(), 0); } else { - httpClient.removeRequestInterceptorByClass(PreemtiveAuthorizationHttpRequestInterceptor.class); + httpClient.removeRequestInterceptorByClass(PreemptiveAuthorizationHttpRequestInterceptor.class); } } diff --git a/library/src/main/java/com/loopj/android/http/PreemtiveAuthorizationHttpRequestInterceptor.java b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java old mode 100755 new mode 100644 similarity index 95% rename from library/src/main/java/com/loopj/android/http/PreemtiveAuthorizationHttpRequestInterceptor.java rename to library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java index 3f52da79b..d3832c6da --- a/library/src/main/java/com/loopj/android/http/PreemtiveAuthorizationHttpRequestInterceptor.java +++ b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java @@ -33,7 +33,7 @@ import java.io.IOException; -public class PreemtiveAuthorizationHttpRequestInterceptor implements HttpRequestInterceptor { +public class PreemptiveAuthorizationHttpRequestInterceptor implements HttpRequestInterceptor { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); From b77e02a106a6e284e155e3af84d8d7e83e33f5d6 Mon Sep 17 00:00:00 2001 From: "zhuleiv5@outlook.com" Date: Fri, 17 Apr 2015 17:59:31 +0800 Subject: [PATCH 051/167] add RequestParams put files array --- library/build.gradle | 6 +- .../com/loopj/android/http/RequestParams.java | 72 +++++++++++++++++-- sample/build.gradle | 6 +- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 6f5a9d3cb..d05b0b66e 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 22 - buildToolsVersion '22.0.1' + compileSdkVersion 21 + buildToolsVersion '21.1.2' defaultConfig { minSdkVersion 3 - targetSdkVersion 22 + targetSdkVersion 21 } lintOptions { diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 1d0e3f4a0..095134b9c 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -73,6 +73,9 @@ * String[] colors = { "blue", "yellow" }; // Ordered collection * params.put("colors", colors); // url params: "colors[]=blue&colors[]=yellow" * + * File[] files = { new File("pic.jpg"), new File("pic1.jpg") }; // Ordered collection + * params.put("files", files); // url params: "files[]=pic.jpg&files[]=pic1.jpg" + * * List<Map<String, String>> listOfMaps = new ArrayList<Map<String, * String>>(); * Map<String, String> user1 = new HashMap<String, String>(); @@ -106,6 +109,7 @@ public class RequestParams implements Serializable { protected final ConcurrentHashMap urlParams = new ConcurrentHashMap(); protected final ConcurrentHashMap streamParams = new ConcurrentHashMap(); protected final ConcurrentHashMap fileParams = new ConcurrentHashMap(); + protected final ConcurrentHashMap >fileArrayParams = new ConcurrentHashMap>(); protected final ConcurrentHashMap urlParamsWithObjects = new ConcurrentHashMap(); protected String contentEncoding = HTTP.UTF_8; @@ -113,7 +117,7 @@ public class RequestParams implements Serializable { * Sets content encoding for return value of {@link #getParamString()} and {@link * #createFormEntity()}

 

Default encoding is "UTF-8" * - * @param encoding String constant from {@link org.apache.http.protocol.HTTP} + * @param encoding String constant from {@link HTTP} */ public void setContentEncoding(final String encoding) { if (encoding != null) { @@ -200,12 +204,47 @@ public void put(String key, String value) { } } + /** + * Adds files array to the request. + * + * @param key the key name for the new param. + * @param files the files array to add. + * @throws FileNotFoundException + */ + public void put(String key, File files[]) throws FileNotFoundException { + put(key, files, null, null); + } + + /** + * + * Adds files array to the request with both custom provided file content-type and files name + * + * @param key the key name for the new param. + * @param files the files array to add. + * @param contentType the content type of the file, eg. application/json + * @param customFileName file name to use instead of real file name + * @throws FileNotFoundException throws if wrong File argument was passed + */ + public void put(String key, File files[], String contentType, String customFileName) throws FileNotFoundException { + + if(key != null){ + List fileWrappers = new ArrayList(); + for (int i=0;i> entry : fileArrayParams.entrySet()) { + if (result.length() > 0) + result.append("&"); + + result.append(entry.getKey()); + result.append("="); + result.append("FILE"); + } + List params = getParamsList(null, urlParamsWithObjects); for (BasicNameValuePair kv : params) { if (result.length() > 0) @@ -469,7 +519,7 @@ public void setAutoCloseInputStreams(boolean flag) { public HttpEntity getEntity(ResponseHandlerInterface progressHandler) throws IOException { if (useJsonStreamer) { return createJsonStreamerEntity(progressHandler); - } else if (!forceMultipartEntity && streamParams.isEmpty() && fileParams.isEmpty()) { + } else if (!forceMultipartEntity && streamParams.isEmpty() && fileParams.isEmpty() && fileArrayParams.isEmpty()) { return createFormEntity(); } else { return createMultipartEntity(progressHandler); @@ -553,6 +603,14 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle entity.addPart(entry.getKey(), fileWrapper.file, fileWrapper.contentType, fileWrapper.customFileName); } + // Add file collection + for (ConcurrentHashMap.Entry> entry : fileArrayParams.entrySet()) { + List fileWrapper = entry.getValue(); + for (FileWrapper fw:fileWrapper){ + entity.addPart(entry.getKey(), fw.file, fw.contentType, fw.customFileName); + } + } + return entity; } diff --git a/sample/build.gradle b/sample/build.gradle index 370f59ff6..84507453c 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -8,12 +8,12 @@ repositories { } android { - compileSdkVersion 22 - buildToolsVersion '22.0.1' + compileSdkVersion 21 + buildToolsVersion '21.1.2' defaultConfig { minSdkVersion 3 - targetSdkVersion 22 + targetSdkVersion 21 } compileOptions { From 521f7516792d03615a27c23e816858762243ff36 Mon Sep 17 00:00:00 2001 From: "zhuleiv5@outlook.com" Date: Fri, 17 Apr 2015 18:07:47 +0800 Subject: [PATCH 052/167] old --- library/build.gradle | 6 +++--- sample/build.gradle | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index d05b0b66e..6f5a9d3cb 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22.0.1' defaultConfig { minSdkVersion 3 - targetSdkVersion 21 + targetSdkVersion 22 } lintOptions { diff --git a/sample/build.gradle b/sample/build.gradle index 84507453c..370f59ff6 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -8,12 +8,12 @@ repositories { } android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22.0.1' defaultConfig { minSdkVersion 3 - targetSdkVersion 21 + targetSdkVersion 22 } compileOptions { From fddb256574ce379eb542cb7c72d34e370ed807af Mon Sep 17 00:00:00 2001 From: Alex Liang Date: Tue, 5 May 2015 16:19:51 +0800 Subject: [PATCH 053/167] Fix java.util.ConcurrentModificationException of AsyncHttpClient. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the issue that AsyncHttpClient‘s method public void cancelRequests(final Context context, final boolean mayInterruptIfRunning) may throw ConcurrentModificationException. --- .../loopj/android/http/AsyncHttpClient.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 7c7fa3036..7a436257c 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -721,22 +721,28 @@ public void cancelRequests(final Context context, final boolean mayInterruptIfRu Log.e(LOG_TAG, "Passed null Context to cancelRequests"); return; } - Runnable r = new Runnable() { - @Override - public void run() { - List requestList = requestMap.get(context); - if (requestList != null) { - for (RequestHandle requestHandle : requestList) { - requestHandle.cancel(mayInterruptIfRunning); - } - requestMap.remove(context); - } - } - }; + + final List requestList = requestMap.get(context); + requestMap.remove(context); + if (Looper.myLooper() == Looper.getMainLooper()) { - new Thread(r).start(); + Runnable runnable = new Runnable() { + @Override + public void run() { + cancelRequests(requestList, mayInterruptIfRunning); + } + }; + threadPool.submit(runnable); } else { - r.run(); + cancelRequests(requestList, mayInterruptIfRunning); + } + } + + private void cancelRequests(final List requestList, final boolean mayInterruptIfRunning) { + if (requestList != null) { + for (RequestHandle requestHandle : requestList) { + requestHandle.cancel(mayInterruptIfRunning); + } } } From 186def7d584cba391a033f85ad94c0e9ac755638 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 14:31:33 +0200 Subject: [PATCH 054/167] Updated build dependencies --- build.gradle | 2 +- sample/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index cfa2b19b0..589fb8ead 100755 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.2.2' } } diff --git a/sample/build.gradle b/sample/build.gradle index 370f59ff6..7bfe11fa4 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -37,6 +37,6 @@ android { } dependencies { - compile 'com.fasterxml.jackson.core:jackson-databind:2.4.3' + compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3' compile project(':library') } From f4db52c68a15c4c387f2a1781f1b9a788497a8b3 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 14:40:39 +0200 Subject: [PATCH 055/167] onProgress now returns Long results, for sake of dealing with large files, Closes #847 --- .../loopj/android/http/AsyncHttpResponseHandler.java | 12 +++++++----- .../android/http/DataAsyncHttpResponseHandler.java | 3 ++- .../android/http/FileAsyncHttpResponseHandler.java | 2 +- .../com/loopj/android/http/JsonStreamerEntity.java | 7 ++++--- .../http/RangeFileAsyncHttpResponseHandler.java | 2 +- .../loopj/android/http/ResponseHandlerInterface.java | 6 +++--- .../loopj/android/http/SimpleMultipartEntity.java | 7 ++++--- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index f03c1423b..9ee484f6e 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -78,6 +78,7 @@ * }); * */ +@SuppressWarnings("ALL") public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterface { private static final String LOG_TAG = "AsyncHttpResponseHandler"; @@ -246,7 +247,7 @@ public String getCharset() { * @param bytesWritten offset from start of file * @param totalSize total size of file */ - public void onProgress(int bytesWritten, int totalSize) { + public void onProgress(long bytesWritten, long totalSize) { Log.v(LOG_TAG, String.format("Progress %d from %d (%2.0f%%)", bytesWritten, totalSize, (totalSize > 0) ? (bytesWritten * 1.0 / totalSize) * 100 : -1)); } @@ -313,7 +314,7 @@ public void onUserException(Throwable error) { } @Override - final public void sendProgressMessage(int bytesWritten, int bytesTotal) { + final public void sendProgressMessage(long bytesWritten, long bytesTotal) { sendMessage(obtainMessage(PROGRESS_MESSAGE, new Object[]{bytesWritten, bytesTotal})); } @@ -379,7 +380,7 @@ protected void handleMessage(Message message) { response = (Object[]) message.obj; if (response != null && response.length >= 2) { try { - onProgress((Integer) response[0], (Integer) response[1]); + onProgress((Long) response[0], (Long) response[1]); } catch (Throwable t) { Log.e(LOG_TAG, "custom onProgress contains an error", t); } @@ -480,12 +481,13 @@ byte[] getResponseData(HttpEntity entity) throws IOException { ByteArrayBuffer buffer = new ByteArrayBuffer(buffersize); try { byte[] tmp = new byte[BUFFER_SIZE]; - int l, count = 0; + long count = 0; + int l; // do not send messages if request has been cancelled while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { count += l; buffer.append(tmp, 0, l); - sendProgressMessage(count, (int) (contentLength <= 0 ? 1 : contentLength)); + sendProgressMessage(count, (contentLength <= 0 ? 1 : contentLength)); } } finally { AsyncHttpClient.silentCloseInputStream(instream); diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index d801c9faf..deb0bd809 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.InputStream; +@SuppressWarnings("ALL") public abstract class DataAsyncHttpResponseHandler extends AsyncHttpResponseHandler { private static final String LOG_TAG = "DataAsyncHttpResponseHandler"; @@ -105,7 +106,7 @@ byte[] getResponseData(HttpEntity entity) throws IOException { while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { buffer.append(tmp, 0, l); sendProgressDataMessage(copyOfRange(tmp, 0, l)); - sendProgressMessage(count, (int) contentLength); + sendProgressMessage(count, contentLength); } } finally { AsyncHttpClient.silentCloseInputStream(instream); diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 1a11a1a08..8337d829d 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -153,7 +153,7 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { count += l; buffer.write(tmp, 0, l); - sendProgressMessage(count, (int) contentLength); + sendProgressMessage(count, contentLength); } } finally { AsyncHttpClient.silentCloseInputStream(instream); diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index b65b42710..5bc2761ce 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -83,8 +83,8 @@ public JsonStreamerEntity(ResponseHandlerInterface progressHandler, boolean useG this.progressHandler = progressHandler; this.contentEncoding = useGZipCompression ? HEADER_GZIP_ENCODING : null; this.elapsedField = TextUtils.isEmpty(elapsedField) - ? null - : escape(elapsedField); + ? null + : escape(elapsedField); } /** @@ -283,7 +283,8 @@ private void writeToFromFile(OutputStream os, RequestParams.FileWrapper wrapper) // Send the meta data. writeMetaData(os, wrapper.file.getName(), wrapper.contentType); - int bytesRead, bytesWritten = 0, totalSize = (int) wrapper.file.length(); + int bytesRead; + long bytesWritten = 0, totalSize = wrapper.file.length(); // Open the file for reading. FileInputStream in = new FileInputStream(wrapper.file); diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index 7abffb1a4..480e8da75 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -88,7 +88,7 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { while (current < contentLength && (l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { current += l; buffer.write(tmp, 0, l); - sendProgressMessage((int) current, (int) contentLength); + sendProgressMessage(current, contentLength); } } finally { instream.close(); diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index 6660683c8..605d142fa 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -53,7 +53,7 @@ public interface ResponseHandlerInterface { * @param bytesWritten number of written bytes * @param bytesTotal number of total bytes to be written */ - void sendProgressMessage(int bytesWritten, int bytesTotal); + void sendProgressMessage(long bytesWritten, long bytesTotal); /** * Notifies callback, that request was cancelled @@ -148,7 +148,7 @@ public interface ResponseHandlerInterface { * This method is called once by the system when the response is about to be * processed by the system. The library makes sure that a single response * is pre-processed only once. - * + *

* Please note: pre-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. @@ -162,7 +162,7 @@ public interface ResponseHandlerInterface { * This method is called once by the system when the request has been fully * sent, handled and finished. The library makes sure that a single response * is post-processed only once. - * + *

* Please note: post-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index a6883068d..cd9c67436 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -69,9 +69,9 @@ class SimpleMultipartEntity implements HttpEntity { private final ResponseHandlerInterface progressHandler; - private int bytesWritten; + private long bytesWritten; - private int totalSize; + private long totalSize; public SimpleMultipartEntity(ResponseHandlerInterface progressHandler) { final StringBuilder buf = new StringBuilder(); @@ -117,6 +117,7 @@ public void addPart(String key, File file) { public void addPart(String key, File file, String type) { fileParts.add(new FilePart(key, file, normalizeContentType(type))); } + public void addPart(String key, File file, String type, String customFileName) { fileParts.add(new FilePart(key, file, normalizeContentType(type), customFileName)); } @@ -167,7 +168,7 @@ private byte[] createContentDisposition(String key, String fileName) { "; filename=\"" + fileName + "\"" + STR_CR_LF).getBytes(); } - private void updateProgress(int count) { + private void updateProgress(long count) { bytesWritten += count; progressHandler.sendProgressMessage(bytesWritten, totalSize); } From 6bcb0a9cbc5a3f0f42b4b527a08a6aac3113ff96 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 15:00:57 +0200 Subject: [PATCH 056/167] Updated documentation, javadocs and formatted code --- CHANGELOG.md | 6 +++++ .../loopj/android/http/AsyncHttpClient.java | 20 ++++++++++------ .../http/AsyncHttpResponseHandler.java | 2 +- .../com/loopj/android/http/HttpDelete.java | 10 +++++--- .../java/com/loopj/android/http/HttpGet.java | 10 +++++--- .../com/loopj/android/http/HttpPatch.java | 17 +++++++++----- .../android/http/JsonValueInterface.java | 2 +- .../com/loopj/android/http/RequestParams.java | 23 +++++++++---------- .../http/ResponseHandlerInterface.java | 12 +++++----- .../http/SaxAsyncHttpResponseHandler.java | 8 +++---- 10 files changed, 67 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 948f7b1f0..8086f6ece 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ - Added support for HTTP PATCH requests - Fixed Assert exception when mkdirs in FileAsyncHttpResponseHandler tries to create dirs that already exists - Provided option to easily override ClientConnectionManager provision in AsyncHttpClient + - Changed onProgress from (int,int) to (long,long) for dealing with large transfers + - Renamed typo of `preemtive` to `preemptive` (preemptive basic auth) + - Added option to put File array in RequestParams + - RequestParams now support forcing Content-Type into `multipart/form-data` even if there are no files/streams to be multiparted + - Gradle added support for installing to local maven repository, through `gradle installArchives` task + - Added support for Json RFC5179 in JsonHttpResponseHandler ## 1.4.6 (released 7. 9. 2014) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 7c7fa3036..37980f83e 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -632,8 +632,8 @@ public void setBasicAuth(String username, String password) { * Sets basic authentication for the request. Uses AuthScope.ANY. This is the same as * setBasicAuth('username','password',AuthScope.ANY) * - * @param username Basic Auth username - * @param password Basic Auth password + * @param username Basic Auth username + * @param password Basic Auth password * @param preemptive sets authorization in preemptive manner */ public void setBasicAuth(String username, String password, boolean preemptive) { @@ -656,9 +656,9 @@ public void setBasicAuth(String username, String password, AuthScope scope) { * Sets basic authentication for the request. You should pass in your AuthScope for security. It * should be like this setBasicAuth("username","password", new AuthScope("host",port,AuthScope.ANY_REALM)) * - * @param username Basic Auth username - * @param password Basic Auth password - * @param scope an AuthScope object + * @param username Basic Auth username + * @param password Basic Auth password + * @param scope an AuthScope object * @param preemptive sets authorization in preemptive manner */ public void setBasicAuth(String username, String password, AuthScope scope, boolean preemptive) { @@ -1095,7 +1095,8 @@ public RequestHandle put(Context context, String url, Header[] headers, HttpEnti } /** - * Perform a HTTP PATCH request, without any parameters. + * Perform a HTTP + * request, without any parameters. * * @param url the URL to send the request to. * @param responseHandler the response handler instance that should handle the response. @@ -1136,6 +1137,11 @@ public RequestHandle patch(Context context, String url, RequestParams params, Re * @param context the Android Context which initiated the request. * @param url the URL to send the request to. * @param responseHandler the response handler instance that should handle the response. + * @param entity a raw {@link HttpEntity} to send with the request, for example, use + * this to send string/json/xml payloads to a server by passing a {@link + * org.apache.http.entity.StringEntity} + * @param contentType the content type of the payload you are sending, for example + * "application/json" if sending a json payload. * @return RequestHandle of future request process */ public RequestHandle patch(Context context, String url, HttpEntity entity, String contentType, ResponseHandlerInterface responseHandler) { @@ -1397,7 +1403,7 @@ public static String getUrlWithQueryString(boolean shouldEncodeUrl, String url, * * @param inputStream InputStream to be checked * @return true or false if the stream contains GZIP compressed data - * @throws java.io.IOException + * @throws java.io.IOException if read from inputStream fails */ public static boolean isInputStreamGZIPCompressed(final PushbackInputStream inputStream) throws IOException { if (inputStream == null) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 9ee484f6e..24b5cc2f6 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -39,7 +39,7 @@ * {@link #onSuccess(int, org.apache.http.Header[], byte[])} method is designed to be anonymously * overridden with your own response handling code.

 

Additionally, you can override the * {@link #onFailure(int, org.apache.http.Header[], byte[], Throwable)}, {@link #onStart()}, {@link - * #onFinish()}, {@link #onRetry(int)} and {@link #onProgress(int, int)} methods as required. + * #onFinish()}, {@link #onRetry(int)} and {@link #onProgress(long, long)} methods as required. *

 

For example:

 

*
  * AsyncHttpClient client = new AsyncHttpClient();
diff --git a/library/src/main/java/com/loopj/android/http/HttpDelete.java b/library/src/main/java/com/loopj/android/http/HttpDelete.java
index 7bd0d10b2..fa5287290 100644
--- a/library/src/main/java/com/loopj/android/http/HttpDelete.java
+++ b/library/src/main/java/com/loopj/android/http/HttpDelete.java
@@ -35,17 +35,21 @@ public HttpDelete() {
         super();
     }
 
+    /**
+     * @param uri target url as URI
+     */
     public HttpDelete(final URI uri) {
         super();
         setURI(uri);
     }
 
     /**
+     * @param uri target url as String
      * @throws IllegalArgumentException if the uri is invalid.
-    */
+     */
     public HttpDelete(final String uri) {
-            super();
-            setURI(URI.create(uri));
+        super();
+        setURI(URI.create(uri));
     }
 
     @Override
diff --git a/library/src/main/java/com/loopj/android/http/HttpGet.java b/library/src/main/java/com/loopj/android/http/HttpGet.java
index 880f3c76f..4c639e8c2 100644
--- a/library/src/main/java/com/loopj/android/http/HttpGet.java
+++ b/library/src/main/java/com/loopj/android/http/HttpGet.java
@@ -36,17 +36,21 @@ public HttpGet() {
         super();
     }
 
+    /**
+     * @param uri target url as URI
+     */
     public HttpGet(final URI uri) {
         super();
         setURI(uri);
     }
 
     /**
+     * @param uri target url as String
      * @throws IllegalArgumentException if the uri is invalid.
-    */
+     */
     public HttpGet(final String uri) {
-            super();
-            setURI(URI.create(uri));
+        super();
+        setURI(URI.create(uri));
     }
 
     @Override
diff --git a/library/src/main/java/com/loopj/android/http/HttpPatch.java b/library/src/main/java/com/loopj/android/http/HttpPatch.java
index a81cc2c54..f0963d409 100644
--- a/library/src/main/java/com/loopj/android/http/HttpPatch.java
+++ b/library/src/main/java/com/loopj/android/http/HttpPatch.java
@@ -18,33 +18,38 @@
 
 package com.loopj.android.http;
 
-import java.net.URI;
 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
 
+import java.net.URI;
+
 /**
  * The current Android (API level 21) bundled version of the Apache Http Client does not implement
- * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. 
+ * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead.
  * This implementation can and should go away when the official solution arrives.
  */
 public final class HttpPatch extends HttpEntityEnclosingRequestBase {
-	
+
     public final static String METHOD_NAME = "PATCH";
 
     public HttpPatch() {
         super();
     }
 
+    /**
+     * @param uri target url as URI
+     */
     public HttpPatch(final URI uri) {
         super();
         setURI(uri);
     }
 
     /**
+     * @param uri target url as String
      * @throws IllegalArgumentException if the uri is invalid.
-    */
+     */
     public HttpPatch(final String uri) {
-            super();
-            setURI(URI.create(uri));
+        super();
+        setURI(URI.create(uri));
     }
 
     @Override
diff --git a/library/src/main/java/com/loopj/android/http/JsonValueInterface.java b/library/src/main/java/com/loopj/android/http/JsonValueInterface.java
index 110b5c1c3..3d84513a7 100644
--- a/library/src/main/java/com/loopj/android/http/JsonValueInterface.java
+++ b/library/src/main/java/com/loopj/android/http/JsonValueInterface.java
@@ -24,7 +24,7 @@
  * not rely on {@link org.json.JSONArray} or {@link org.json.JSONObject} to
  * exchange data.
  *
- * @author Noor Dawod 
+ * @author Noor Dawod {@literal }
  */
 public interface JsonValueInterface {
 
diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java
index 095134b9c..5fcb28d95 100755
--- a/library/src/main/java/com/loopj/android/http/RequestParams.java
+++ b/library/src/main/java/com/loopj/android/http/RequestParams.java
@@ -109,7 +109,7 @@ public class RequestParams implements Serializable {
     protected final ConcurrentHashMap urlParams = new ConcurrentHashMap();
     protected final ConcurrentHashMap streamParams = new ConcurrentHashMap();
     protected final ConcurrentHashMap fileParams = new ConcurrentHashMap();
-    protected final ConcurrentHashMap >fileArrayParams = new ConcurrentHashMap>();
+    protected final ConcurrentHashMap> fileArrayParams = new ConcurrentHashMap>();
     protected final ConcurrentHashMap urlParamsWithObjects = new ConcurrentHashMap();
     protected String contentEncoding = HTTP.UTF_8;
 
@@ -130,7 +130,7 @@ public void setContentEncoding(final String encoding) {
     /**
      * If set to true will force Content-Type header to `multipart/form-data`
      * even if there are not Files or Streams to be send
-     *
+     * 

 

* Default value is false * * @param force boolean, should declare content-type multipart/form-data even without files or streams present @@ -207,35 +207,34 @@ public void put(String key, String value) { /** * Adds files array to the request. * - * @param key the key name for the new param. + * @param key the key name for the new param. * @param files the files array to add. - * @throws FileNotFoundException + * @throws FileNotFoundException if one of passed files is not found at time of assembling the requestparams into request */ public void put(String key, File files[]) throws FileNotFoundException { put(key, files, null, null); } /** - * * Adds files array to the request with both custom provided file content-type and files name * * @param key the key name for the new param. - * @param files the files array to add. + * @param files the files array to add. * @param contentType the content type of the file, eg. application/json * @param customFileName file name to use instead of real file name * @throws FileNotFoundException throws if wrong File argument was passed */ public void put(String key, File files[], String contentType, String customFileName) throws FileNotFoundException { - if(key != null){ + if (key != null) { List fileWrappers = new ArrayList(); - for (int i=0;i 

* To disable this feature, call this method with null as the field value. * * @param value field name to add elapsed time, or null to disable @@ -606,7 +605,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle // Add file collection for (ConcurrentHashMap.Entry> entry : fileArrayParams.entrySet()) { List fileWrapper = entry.getValue(); - for (FileWrapper fw:fileWrapper){ + for (FileWrapper fw : fileWrapper) { entity.addPart(entry.getKey(), fw.file, fw.contentType, fw.customFileName); } } diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index 605d142fa..e438e68a2 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -91,28 +91,28 @@ public interface ResponseHandlerInterface { * * @return uri of origin request */ - public URI getRequestURI(); + URI getRequestURI(); /** * Returns Header[] which were used to request * * @return headers from origin request */ - public Header[] getRequestHeaders(); + Header[] getRequestHeaders(); /** * Helper for handlers to receive Request URI info * * @param requestURI claimed request URI */ - public void setRequestURI(URI requestURI); + void setRequestURI(URI requestURI); /** * Helper for handlers to receive Request Header[] info * * @param requestHeaders Headers, claimed to be from original request */ - public void setRequestHeaders(Header[] requestHeaders); + void setRequestHeaders(Header[] requestHeaders); /** * Can set, whether the handler should be asynchronous or synchronous @@ -148,7 +148,7 @@ public interface ResponseHandlerInterface { * This method is called once by the system when the response is about to be * processed by the system. The library makes sure that a single response * is pre-processed only once. - *

+ *

 

* Please note: pre-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. @@ -162,7 +162,7 @@ public interface ResponseHandlerInterface { * This method is called once by the system when the request has been fully * sent, handled and finished. The library makes sure that a single response * is post-processed only once. - *

+ *

 

* Please note: post-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index f4663b7bb..39a564337 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -38,11 +38,11 @@ /** * Provides interface to deserialize SAX responses, using AsyncHttpResponseHandler. Can be used like * this - * + *

 

*
  *     AsyncHttpClient ahc = new AsyncHttpClient();
  *     FontHandler handlerInstance = ... ; // init handler instance
- *     ahc.post("https://server.tld/api/call", new SaxAsyncHttpResponseHandler(handlerInstance){
+ *     ahc.post("https://server.tld/api/call", new SaxAsyncHttpResponseHandler{@literal <}FontHandler{@literal >}(handlerInstance){
  *         @Override
  *         public void onSuccess(int statusCode, Header[] headers, FontHandler t) {
  *              // Request got HTTP success statusCode
@@ -52,7 +52,7 @@
  *              // Request got HTTP fail statusCode
  *         }
  *     });
- * 
+ * 
* * @param Handler extending {@link org.xml.sax.helpers.DefaultHandler} * @see org.xml.sax.helpers.DefaultHandler @@ -85,7 +85,7 @@ public SaxAsyncHttpResponseHandler(T t) { * * @param entity returned HttpEntity * @return deconstructed response - * @throws java.io.IOException + * @throws java.io.IOException if there is problem assembling SAX response from stream * @see org.apache.http.HttpEntity */ @Override From fe1c8640f82626f4776a8115704a7b4db5d9af7d Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 15:25:38 +0200 Subject: [PATCH 057/167] Not overriding Content-Type header if HttpEntityEnclosingRequestBase doesn't provide one, Closing #838 --- .../src/main/java/com/loopj/android/http/AsyncHttpClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 37980f83e..f05d26675 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1298,9 +1298,9 @@ protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpCo if (responseHandler.getUseSynchronousMode() && !responseHandler.getUsePoolThread()) { throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead."); } - + if (contentType != null) { - if (uriRequest instanceof HttpEntityEnclosingRequestBase && ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != null) { + if (uriRequest instanceof HttpEntityEnclosingRequestBase && ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != null && uriRequest.containsHeader(HEADER_CONTENT_TYPE)) { Log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type"); } else { uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType); From d39105aac323e2c6403930cd77783262831e2e2b Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 18:49:14 +0200 Subject: [PATCH 058/167] Release of 1.4.7 --- CHANGELOG.md | 2 +- README.md | 16 ++++++++-------- build.gradle | 2 +- gradle.properties | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8086f6ece..6a3aeb5ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## 1.4.7 (future version) +## 1.4.7 (released 9. 5. 2015) - Fixed crash when canceling through RequestHandle from UI Thread (NetworkOnMainThreadException) - Fixed URL encoding feature, that was breaking whole URL, not just path and query parts diff --git a/README.md b/README.md index de4656d3f..8a48b11e6 100755 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ An asynchronous, callback-based Http client for Android built on top of Apache's Changelog --------- -See what is new in version 1.4.6 released on 7th Sep 2014 +See what is new in version 1.4.7 released on 9th May 2015 -https://github.com/loopj/android-async-http/blob/1.4.6/CHANGELOG.md +https://github.com/loopj/android-async-http/blob/1.4.7/CHANGELOG.md Javadoc ------- -Latest Javadoc for 1.4.6 release are available here (also included in Maven repository): +Latest Javadoc for 1.4.7 release are available here (also included in Maven repository): http://loopj.com/android-async-http/doc/ @@ -35,7 +35,7 @@ Examples -------- For inspiration and testing on device we've provided Sample Application. -See individual samples [here on Github](https://github.com/loopj/android-async-http/tree/1.4.6/sample/src/main/java/com/loopj/android/http/sample) +See individual samples [here on Github](https://github.com/loopj/android-async-http/tree/1.4.7/sample/src/main/java/com/loopj/android/http/sample) To run Sample application, simply clone the repository and run this command, to install it on connected device ```java @@ -53,10 +53,10 @@ http://central.maven.org/maven2/com/loopj/android/android-async-http/ Maven URL: http://repo1.maven.org/maven2/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.6 +Version: 1.4.7 Packaging: JAR or AAR ``` -Gradle: `com.loopj.android:android-async-http:1.4.6` +Gradle: `com.loopj.android:android-async-http:1.4.7` **development snapshots** @@ -65,10 +65,10 @@ https://oss.sonatype.org/content/repositories/snapshots/com/loopj/android/androi Maven URL: https://oss.sonatype.org/content/repositories/snapshots/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.7-SNAPSHOT +Version: 1.4.8-SNAPSHOT Packaging: JAR or AAR ``` -Gradle: `com.loopj.android:android-async-http:1.4.7-SNAPSHOT` +Gradle: `com.loopj.android:android-async-http:1.4.8-SNAPSHOT` Documentation, Features and Examples ------------------------------------ diff --git a/build.gradle b/build.gradle index 589fb8ead..ddad31227 100755 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.4.7-SNAPSHOT' + version = '1.4.7' repositories { mavenCentral() diff --git a/gradle.properties b/gradle.properties index df1bf1ff3..52141c94f 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=1.4.7-SNAPSHOT +VERSION_NAME=1.4.7 VERSION_CODE=147 GROUP=com.loopj.android From db48445a3649daeac213a1e0a4057692ec6aa450 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 18:52:43 +0200 Subject: [PATCH 059/167] Prepare 1.4.8 snapshot development --- build.gradle | 2 +- gradle.properties | 4 ++-- library/src/main/AndroidManifest.xml | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index ddad31227..d6ac9ba18 100755 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.4.7' + version = '1.4.8-SNAPSHOT' repositories { mavenCentral() diff --git a/gradle.properties b/gradle.properties index 52141c94f..c7c5dc86f 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=1.4.7 -VERSION_CODE=147 +VERSION_NAME=1.4.8-SNAPSHOT +VERSION_CODE=148 GROUP=com.loopj.android POM_DESCRIPTION=An Asynchronous HTTP Library for Android diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index 58b8a4f53..3049b2d68 100755 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,8 +1,6 @@ + package="com.loopj.android.http"> From e4e5ca18fb670a48f29760fc6689f475c1cc8afd Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 9 May 2015 18:55:20 +0200 Subject: [PATCH 060/167] Updated Gradle wrapper --- gradle/wrapper/gradle-wrapper.jar | Bin 52141 -> 52266 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 085a1cdc27db1185342f15a00441734e74fe3735..b5166dad4d90021f6a0b45268c0755719f1d5cd4 100644 GIT binary patch delta 8640 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 OP8h~Ugm3;c@_zu%56iCr delta 8509 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 Date: Mon, 11 May 2015 11:40:03 +0200 Subject: [PATCH 061/167] Added missing release JARs --- releases/android-async-http-1.2.0.jar | Bin releases/android-async-http-1.2.1.jar | Bin releases/android-async-http-1.3.0.jar | Bin releases/android-async-http-1.3.1.jar | Bin releases/android-async-http-1.3.2.jar | Bin releases/android-async-http-1.4.0.jar | Bin releases/android-async-http-1.4.1.jar | Bin releases/android-async-http-1.4.2.jar | Bin releases/android-async-http-1.4.3.jar | Bin releases/android-async-http-1.4.4.jar | Bin releases/android-async-http-1.4.5.jar | Bin releases/android-async-http-1.4.6.jar | Bin 0 -> 95377 bytes releases/android-async-http-1.4.7.jar | Bin 0 -> 101155 bytes 13 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 releases/android-async-http-1.2.0.jar mode change 100755 => 100644 releases/android-async-http-1.2.1.jar mode change 100755 => 100644 releases/android-async-http-1.3.0.jar mode change 100755 => 100644 releases/android-async-http-1.3.1.jar mode change 100755 => 100644 releases/android-async-http-1.3.2.jar mode change 100755 => 100644 releases/android-async-http-1.4.0.jar mode change 100755 => 100644 releases/android-async-http-1.4.1.jar mode change 100755 => 100644 releases/android-async-http-1.4.2.jar mode change 100755 => 100644 releases/android-async-http-1.4.3.jar mode change 100755 => 100644 releases/android-async-http-1.4.4.jar mode change 100755 => 100644 releases/android-async-http-1.4.5.jar create mode 100644 releases/android-async-http-1.4.6.jar create mode 100644 releases/android-async-http-1.4.7.jar diff --git a/releases/android-async-http-1.2.0.jar b/releases/android-async-http-1.2.0.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.2.1.jar b/releases/android-async-http-1.2.1.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.3.0.jar b/releases/android-async-http-1.3.0.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.3.1.jar b/releases/android-async-http-1.3.1.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.3.2.jar b/releases/android-async-http-1.3.2.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.0.jar b/releases/android-async-http-1.4.0.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.1.jar b/releases/android-async-http-1.4.1.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.2.jar b/releases/android-async-http-1.4.2.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.3.jar b/releases/android-async-http-1.4.3.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.4.jar b/releases/android-async-http-1.4.4.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.5.jar b/releases/android-async-http-1.4.5.jar old mode 100755 new mode 100644 diff --git a/releases/android-async-http-1.4.6.jar b/releases/android-async-http-1.4.6.jar new file mode 100644 index 0000000000000000000000000000000000000000..70391cb95beb578d9e9bf69844473ed7857bbb4b GIT binary patch literal 95377 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 BrZxZo literal 0 HcmV?d00001 diff --git a/releases/android-async-http-1.4.7.jar b/releases/android-async-http-1.4.7.jar new file mode 100644 index 0000000000000000000000000000000000000000..d9e203e5f2b43a6078ce7a6f1d9c4acef147ab80 GIT binary patch literal 101155 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 literal 0 HcmV?d00001 From 775c858d4786e700dacc118c2ff95ed5309e7b81 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Mon, 25 May 2015 13:29:50 +0200 Subject: [PATCH 062/167] Updated Android Gradle plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d6ac9ba18..94018ee29 100755 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.android.tools.build:gradle:1.2.3' } } From d819e129b12037193c0f86056697e98133609bd0 Mon Sep 17 00:00:00 2001 From: "Scott E. Frank" Date: Fri, 29 May 2015 17:11:10 -0400 Subject: [PATCH 063/167] Added constructor that also takes a looper --- .../android/http/BinaryHttpResponseHandler.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index 539a263fa..05fcdfe91 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -18,6 +18,7 @@ package com.loopj.android.http; +import android.os.Looper; import android.util.Log; import org.apache.http.Header; @@ -91,6 +92,22 @@ public BinaryHttpResponseHandler(String[] allowedContentTypes) { Log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); } } + + /** + * Creates a new BinaryHttpResponseHandler with a user-supplied looper, and overrides the default allowed content types with + * passed String array (hopefully) of content types. + * + * @param allowedContentTypes content types array, eg. 'image/jpeg' or pattern '.*' + * @param looper The looper to work with + */ + public BinaryHttpResponseHandler(String[] allowedContentTypes, Looper looper) { + super(looper); + if (allowedContentTypes != null) { + mAllowedContentTypes = allowedContentTypes; + } else { + Log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); + } + } @Override public abstract void onSuccess(int statusCode, Header[] headers, byte[] binaryData); From a1162d59770e855dfeb7b48c57407b365ba0f2c9 Mon Sep 17 00:00:00 2001 From: NohSeho Date: Sun, 31 May 2015 23:58:51 +0900 Subject: [PATCH 064/167] Fix copyright year in NOTICE.txt. --- NOTICE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE.txt b/NOTICE.txt index 283826a13..aea75d844 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Android Async Http Client library -Copyright (c) 2011-2014 James Smith +Copyright (c) 2011-2015 James Smith http://loopj.com This product includes software developed by From c49d907975aeb03b2a7294df28bdaa0487eebee4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 1 Jul 2015 13:16:05 +0200 Subject: [PATCH 065/167] Renamed "mFile" (38,08%) to "file" (61,92%) The naturalize tool detected that using "file" is more consistent with the current codebase state. --- .../android/http/FileAsyncHttpResponseHandler.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 8337d829d..fd589cd37 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -31,7 +31,7 @@ public abstract class FileAsyncHttpResponseHandler extends AsyncHttpResponseHandler { - protected final File mFile; + protected final File file; protected final boolean append; private static final String LOG_TAG = "FileAsyncHttpResponseHandler"; @@ -57,7 +57,7 @@ public FileAsyncHttpResponseHandler(File file, boolean append) { if (!file.getParentFile().isDirectory()) { Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); } - this.mFile = file; + this.file = file; this.append = append; } @@ -68,7 +68,7 @@ public FileAsyncHttpResponseHandler(File file, boolean append) { */ public FileAsyncHttpResponseHandler(Context context) { super(); - this.mFile = getTemporaryFile(context); + this.file = getTemporaryFile(context); this.append = false; } @@ -105,8 +105,8 @@ protected File getTemporaryFile(Context context) { * @return File file in which the response is stored */ protected File getTargetFile() { - assert (mFile != null); - return mFile; + assert (file != null); + return file; } @Override From cfaf761a28bd6b5305fb81857b5708565b4aa79b Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 1 Jul 2015 13:22:11 +0200 Subject: [PATCH 066/167] Renamed "name" (7,53%) to "key" (70,42%) The naturalize tool detected that using "key" is more consistent with the current codebase state. --- .../main/java/com/loopj/android/http/SerializableCookie.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/SerializableCookie.java b/library/src/main/java/com/loopj/android/http/SerializableCookie.java index 855105b1c..f7e196c03 100755 --- a/library/src/main/java/com/loopj/android/http/SerializableCookie.java +++ b/library/src/main/java/com/loopj/android/http/SerializableCookie.java @@ -61,9 +61,9 @@ private void writeObject(ObjectOutputStream out) throws IOException { } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - String name = (String) in.readObject(); + String key = (String) in.readObject(); String value = (String) in.readObject(); - clientCookie = new BasicClientCookie(name, value); + clientCookie = new BasicClientCookie(key, value); clientCookie.setComment((String) in.readObject()); clientCookie.setDomain((String) in.readObject()); clientCookie.setExpiryDate((Date) in.readObject()); From 3f1cdf7b35bc4b19b08f1e92522309e7bd31ed9d Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 1 Jul 2015 13:32:42 +0200 Subject: [PATCH 067/167] Renamed "context" (21,87%) to "httpContext" (72,96%). The naturalize tool detected that using "httpContext" is more consistent with the current codebase state. --- .../loopj/android/http/sample/PrePostProcessingSample.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java index 3bbf400c7..a2223d02f 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java @@ -126,8 +126,8 @@ public void run() { private class PrePostProcessRequest extends AsyncHttpRequest { - public PrePostProcessRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) { - super(client, context, request, responseHandler); + public PrePostProcessRequest(AbstractHttpClient client, HttpContext httpContext, HttpUriRequest request, ResponseHandlerInterface responseHandler) { + super(client, httpContext, request, responseHandler); } @Override From 82a999b1f6d9aab2c11b697d101b74fb5bdcbeb8 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 1 Jul 2015 13:44:01 +0200 Subject: [PATCH 068/167] Fix renamings missing renamed "mFile" to "file" --- .../loopj/android/http/RangeFileAsyncHttpResponseHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index 480e8da75..b616e7067 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -101,8 +101,8 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { } public void updateRequestHeaders(HttpUriRequest uriRequest) { - if (mFile.exists() && mFile.canWrite()) - current = mFile.length(); + if (file.exists() && file.canWrite()) + current = file.length(); if (current > 0) { append = true; uriRequest.setHeader("Range", "bytes=" + current + "-"); From 66d1d3ebee117a19fd6f011cedc3334c86ee1339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=BE=99?= Date: Fri, 10 Jul 2015 09:40:50 +0800 Subject: [PATCH 069/167] (*)fix response charset bug --- .../com/loopj/android/http/SaxAsyncHttpResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index 39a564337..dd67fb6ec 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -99,7 +99,7 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { SAXParser sparser = sfactory.newSAXParser(); XMLReader rssReader = sparser.getXMLReader(); rssReader.setContentHandler(handler); - inputStreamReader = new InputStreamReader(instream, DEFAULT_CHARSET); + inputStreamReader = new InputStreamReader(instream, getCharset()); rssReader.parse(new InputSource(inputStreamReader)); } catch (SAXException e) { Log.e(LOG_TAG, "getResponseData exception", e); From 9e1816f8036acba740ea667f2f7c58b0e01095c1 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 13:31:02 +0200 Subject: [PATCH 070/167] Renamed long LogCat tags, ResponseHandler -> RH in all cases --- .../main/java/com/loopj/android/http/AsyncHttpRequest.java | 4 ++-- .../java/com/loopj/android/http/AsyncHttpResponseHandler.java | 2 +- .../com/loopj/android/http/BaseJsonHttpResponseHandler.java | 2 +- .../com/loopj/android/http/BinaryHttpResponseHandler.java | 2 +- .../com/loopj/android/http/DataAsyncHttpResponseHandler.java | 2 +- .../com/loopj/android/http/FileAsyncHttpResponseHandler.java | 2 +- .../java/com/loopj/android/http/JsonHttpResponseHandler.java | 2 +- .../loopj/android/http/RangeFileAsyncHttpResponseHandler.java | 2 +- .../com/loopj/android/http/SaxAsyncHttpResponseHandler.java | 2 +- .../java/com/loopj/android/http/SimpleMultipartEntity.java | 2 -- .../java/com/loopj/android/http/TextHttpResponseHandler.java | 2 +- 11 files changed, 11 insertions(+), 13 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index e18494a43..a54a0085c 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -56,7 +56,7 @@ public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriR * This method is called once by the system when the request is about to be * processed by the system. The library makes sure that a single request * is pre-processed only once. - * + *

* Please note: pre-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. @@ -71,7 +71,7 @@ public void onPreProcessRequest(AsyncHttpRequest request) { * This method is called once by the system when the request has been fully * sent, handled and finished. The library makes sure that a single request * is post-processed only once. - * + *

* Please note: post-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 24b5cc2f6..8dd49ffd0 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -81,7 +81,7 @@ @SuppressWarnings("ALL") public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterface { - private static final String LOG_TAG = "AsyncHttpResponseHandler"; + private static final String LOG_TAG = "AsyncHttpRH"; protected static final int SUCCESS_MESSAGE = 0; protected static final int FAILURE_MESSAGE = 1; diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java index bbec96956..e5d5599d0 100755 --- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java @@ -33,7 +33,7 @@ * @param Generic type meant to be returned in callback */ public abstract class BaseJsonHttpResponseHandler extends TextHttpResponseHandler { - private static final String LOG_TAG = "BaseJsonHttpResponseHandler"; + private static final String LOG_TAG = "BaseJsonHttpRH"; /** * Creates a new JsonHttpResponseHandler with default charset "UTF-8" diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index 05fcdfe91..d5c4e3675 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -52,7 +52,7 @@ */ public abstract class BinaryHttpResponseHandler extends AsyncHttpResponseHandler { - private static final String LOG_TAG = "BinaryHttpResponseHandler"; + private static final String LOG_TAG = "BinaryHttpRH"; private String[] mAllowedContentTypes = new String[]{ RequestParams.APPLICATION_OCTET_STREAM, diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index deb0bd809..8b8bfbb63 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -29,7 +29,7 @@ @SuppressWarnings("ALL") public abstract class DataAsyncHttpResponseHandler extends AsyncHttpResponseHandler { - private static final String LOG_TAG = "DataAsyncHttpResponseHandler"; + private static final String LOG_TAG = "DataAsyncHttpRH"; protected static final int PROGRESS_DATA_MESSAGE = 7; diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index fd589cd37..af0fc218a 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -33,7 +33,7 @@ public abstract class FileAsyncHttpResponseHandler extends AsyncHttpResponseHand protected final File file; protected final boolean append; - private static final String LOG_TAG = "FileAsyncHttpResponseHandler"; + private static final String LOG_TAG = "FileAsyncHttpRH"; /** * Obtains new FileAsyncHttpResponseHandler and stores response in passed file diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index 66ebcdac9..33b827a4f 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -37,7 +37,7 @@ */ public class JsonHttpResponseHandler extends TextHttpResponseHandler { - private static final String LOG_TAG = "JsonHttpResponseHandler"; + private static final String LOG_TAG = "JsonHttpRH"; private boolean useRFC5179CompatibilityMode = true; diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index b616e7067..fd96e4d17 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -35,7 +35,7 @@ public abstract class RangeFileAsyncHttpResponseHandler extends FileAsyncHttpResponseHandler { - private static final String LOG_TAG = "RangeFileAsyncHttpResponseHandler"; + private static final String LOG_TAG = "RangeFileAsyncHttpRH"; private long current = 0; private boolean append = false; diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index dd67fb6ec..db658c91a 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -64,7 +64,7 @@ public abstract class SaxAsyncHttpResponseHandler exte * Generic Type of handler */ private T handler = null; - private final static String LOG_TAG = "SaxAsyncHttpResponseHandler"; + private final static String LOG_TAG = "SaxAsyncHttpRH"; /** * Constructs new SaxAsyncHttpResponseHandler with given handler instance diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index cd9c67436..42a2524b7 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -142,8 +142,6 @@ public void addPart(String key, String streamName, InputStream inputStream, Stri out.write(CR_LF); out.flush(); - - AsyncHttpClient.silentCloseOutputStream(out); } private String normalizeContentType(String type) { diff --git a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java index 71f49459d..e755101d5 100755 --- a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java @@ -57,7 +57,7 @@ */ public abstract class TextHttpResponseHandler extends AsyncHttpResponseHandler { - private static final String LOG_TAG = "TextHttpResponseHandler"; + private static final String LOG_TAG = "TextHttpRH"; /** * Creates new instance with default UTF-8 encoding From 66efa98a2338ad19d786941fa1d4a2fa57361c3e Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 13:39:26 +0200 Subject: [PATCH 071/167] Documentation updated along with correct return values from RequestHandle.cancel(boolean), #884 --- .../main/java/com/loopj/android/http/RequestHandle.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index 5185c7499..81018e0cc 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -40,7 +40,8 @@ public RequestHandle(AsyncHttpRequest request) { * thread executing this request should be interrupted in an attempt to stop the request. *

 

After this method returns, subsequent calls to isDone() will always return * true. Subsequent calls to isCancelled() will always return true if this method returned - * true. + * true. Subsequent calls to isDone() will return true either if the request got cancelled by + * this method, or if the request completed normally * * @param mayInterruptIfRunning true if the thread executing this request should be interrupted; * otherwise, in-progress requests are allowed to complete @@ -57,8 +58,11 @@ public void run() { _request.cancel(mayInterruptIfRunning); } }).start(); + // Cannot reliably tell if the request got immediately canceled at this point + // we'll assume it got cancelled + return true; } else { - _request.cancel(mayInterruptIfRunning); + return _request.cancel(mayInterruptIfRunning); } } return false; From 4c12933974380cc4962175655722708e076473e4 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 13:39:54 +0200 Subject: [PATCH 072/167] Fixed old Lint warning/error with 9e1816f8036acba740ea667f2f7c58b0e01095c1 --- library/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 6f5a9d3cb..31d250041 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -14,8 +14,7 @@ android { warningsAsErrors true quiet false showAll true - disable 'OldTargetApi', 'LongLogTag' - // TODO: long log tag should be fixed instead of ignored + disable 'OldTargetApi' } compileOptions { From f2538d966fae9d2c37316dd3faa9432b5ad93e3d Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 13:49:14 +0200 Subject: [PATCH 073/167] Fixed leftover LogCat TAG --- .../java/com/loopj/android/http/BinaryHttpResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index d5c4e3675..6cde969db 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -140,7 +140,7 @@ public final void sendResponseMessage(HttpResponse response) throws IOException foundAllowedContentType = true; } } catch (PatternSyntaxException e) { - Log.e("BinaryHttpResponseHandler", "Given pattern is not valid: " + anAllowedContentType, e); + Log.e(LOG_TAG, "Given pattern is not valid: " + anAllowedContentType, e); } } if (!foundAllowedContentType) { From ddf6f83b7854c8bcbbe8ed234498ae32cd7b96a5 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 13:58:22 +0200 Subject: [PATCH 074/167] Fixed wrong onFailure -> onSuccess fallback, #895 --- .../com/loopj/android/http/SaxAsyncHttpResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index db658c91a..07ae057d2 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -144,6 +144,6 @@ public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - onSuccess(statusCode, headers, handler); + onFailure(statusCode, headers, handler); } } From 4fcc50f1c295cae97d7bf92288a4e8e8fa9eb432 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 14:02:09 +0200 Subject: [PATCH 075/167] Updated javadoc for onProgress after (long,long) to (int,int) change, #897 --- .../java/com/loopj/android/http/AsyncHttpResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 8dd49ffd0..71ada3c84 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -67,7 +67,7 @@ * } * * @Override - * public void onProgress(int bytesWritten, int totalSize) { + * public void onProgress(long bytesWritten, long totalSize) { * // Progress notification * } * From c61a60daab2444431df46919e54188a6804937fd Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 14:44:10 +0200 Subject: [PATCH 076/167] Added Sample flavor with LeakCanary --- sample/build.gradle | 11 +++ sample/src/main/AndroidManifest.xml | 77 ++++++++++--------- .../http/sample/JsonStreamerSample.java | 2 +- .../http/sample/SampleApplication.java | 0 .../http/sample/SampleApplication.java | 37 +++++++++ 5 files changed, 88 insertions(+), 39 deletions(-) rename sample/src/{main => standard}/java/com/loopj/android/http/sample/SampleApplication.java (100%) create mode 100644 sample/src/withLeakCanaryDebug/java/com/loopj/android/http/sample/SampleApplication.java diff --git a/sample/build.gradle b/sample/build.gradle index 7bfe11fa4..d25948b37 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -16,6 +16,15 @@ android { targetSdkVersion 22 } + productFlavors { + standard { + } + withLeakCanary { + minSdkVersion 8 + targetSdkVersion 22 + } + } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 @@ -39,4 +48,6 @@ android { dependencies { compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3' compile project(':library') + // LeakCanary + withLeakCanaryCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 1d180c460..1a4e0bf02 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,56 +1,57 @@ + package="com.loopj.android.http.sample" + android:versionCode="3" + android:versionName="1.4.7"> - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java index cb308af9f..2bc01733c 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java @@ -87,7 +87,7 @@ public boolean isRequestHeadersAllowed() { protected JSONObject getBodyTextAsJSON() { String bodyText = getBodyText(); - if (bodyText != null) { + if (bodyText != null && !bodyText.isEmpty()) { try { return new JSONObject(bodyText); } catch (JSONException e) { diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleApplication.java b/sample/src/standard/java/com/loopj/android/http/sample/SampleApplication.java similarity index 100% rename from sample/src/main/java/com/loopj/android/http/sample/SampleApplication.java rename to sample/src/standard/java/com/loopj/android/http/sample/SampleApplication.java diff --git a/sample/src/withLeakCanaryDebug/java/com/loopj/android/http/sample/SampleApplication.java b/sample/src/withLeakCanaryDebug/java/com/loopj/android/http/sample/SampleApplication.java new file mode 100644 index 000000000..26949393d --- /dev/null +++ b/sample/src/withLeakCanaryDebug/java/com/loopj/android/http/sample/SampleApplication.java @@ -0,0 +1,37 @@ +package com.loopj.android.http.sample; + +import android.annotation.TargetApi; +import android.app.Application; +import android.os.Build; +import android.os.StrictMode; +import android.util.Log; + +import com.squareup.leakcanary.LeakCanary; + +public class SampleApplication extends Application { + + private static final String LOG_TAG = "SampleApplication"; + + @Override + public void onCreate() { + setStrictMode(); + super.onCreate(); + LeakCanary.install(this); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void setStrictMode() { + if (Integer.valueOf(Build.VERSION.SDK) > 3) { + Log.d(LOG_TAG, "Enabling StrictMode policy over Sample application"); + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() + .penaltyDeath() + .build()); + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() + .detectAll() + .penaltyLog() + .build()); + } + } +} From d81e442a3bdbde2b68e76ecd29362bd030bd7b02 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 15:03:49 +0200 Subject: [PATCH 077/167] Fixed LeakCanary flavor lint errors --- sample/build.gradle | 2 +- sample/src/main/AndroidManifest.xml | 1 + .../java/com/loopj/android/http/sample/JsonStreamerSample.java | 3 ++- .../java/com/loopj/android/http/sample/SampleApplication.java | 0 4 files changed, 4 insertions(+), 2 deletions(-) rename sample/src/{withLeakCanaryDebug => withLeakCanary}/java/com/loopj/android/http/sample/SampleApplication.java (100%) diff --git a/sample/build.gradle b/sample/build.gradle index d25948b37..9ddfff4f3 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -35,7 +35,7 @@ android { warningsAsErrors true quiet false showAll true - disable 'OldTargetApi', 'LongLogTag' + disable 'OldTargetApi', 'UnusedAttribute', 'LongLogTag' } packagingOptions { diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 1a4e0bf02..89883f1e3 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java index 2bc01733c..c8044ac2e 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java @@ -18,6 +18,7 @@ package com.loopj.android.http.sample; +import android.text.TextUtils; import android.util.Log; import com.loopj.android.http.AsyncHttpClient; @@ -87,7 +88,7 @@ public boolean isRequestHeadersAllowed() { protected JSONObject getBodyTextAsJSON() { String bodyText = getBodyText(); - if (bodyText != null && !bodyText.isEmpty()) { + if (bodyText != null && TextUtils.isEmpty(bodyText)) { try { return new JSONObject(bodyText); } catch (JSONException e) { diff --git a/sample/src/withLeakCanaryDebug/java/com/loopj/android/http/sample/SampleApplication.java b/sample/src/withLeakCanary/java/com/loopj/android/http/sample/SampleApplication.java similarity index 100% rename from sample/src/withLeakCanaryDebug/java/com/loopj/android/http/sample/SampleApplication.java rename to sample/src/withLeakCanary/java/com/loopj/android/http/sample/SampleApplication.java From 527dae40527abbe314dbe0ac236b745e3146ef09 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 16:28:28 +0200 Subject: [PATCH 078/167] Added RequestParams formatting sample --- sample/src/main/AndroidManifest.xml | 2 +- .../http/sample/RequestParamsDebug.java | 160 ++++++++++++++++++ .../http/sample/WaypointsActivity.java | 5 +- .../android/http/sample/util/API8Util.java | 23 +++ sample/src/main/res/values/strings.xml | 1 + 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java create mode 100644 sample/src/main/java/com/loopj/android/http/sample/util/API8Util.java diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 89883f1e3..d2fa0094a 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -37,7 +37,6 @@ - @@ -51,6 +50,7 @@ + diff --git a/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java b/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java new file mode 100644 index 000000000..3341887c9 --- /dev/null +++ b/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java @@ -0,0 +1,160 @@ +package com.loopj.android.http.sample; + +import android.os.Bundle; +import android.widget.EditText; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.RequestHandle; +import com.loopj.android.http.RequestParams; +import com.loopj.android.http.ResponseHandlerInterface; +import com.loopj.android.http.TextHttpResponseHandler; +import com.loopj.android.http.sample.util.API8Util; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class RequestParamsDebug extends SampleParentActivity { + + public static final String LOG_TAG = "RequestParamsDebug"; + private EditText customParams; + private static final String DEMO_RP_CONTENT = "array=java\n" + + "array=C\n" + + "list=blue\n" + + "list=yellow\n" + + "set=music\n" + + "set=art\n" + + "map=first_name\n" + + "map=last_name\n"; + + @Override + public ResponseHandlerInterface getResponseHandler() { + return new TextHttpResponseHandler() { + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + debugStatusCode(LOG_TAG, statusCode); + debugHeaders(LOG_TAG, headers); + debugResponse(LOG_TAG, responseString); + debugThrowable(LOG_TAG, throwable); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, String responseString) { + debugStatusCode(LOG_TAG, statusCode); + debugHeaders(LOG_TAG, headers); + debugResponse(LOG_TAG, responseString); + } + }; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + customParams = new EditText(this); + customParams.setLines(8); + customParams.setText(DEMO_RP_CONTENT); + customFieldsLayout.addView(customParams); + } + + @Override + public String getDefaultURL() { + return PROTOCOL + "httpbin.org/get"; + } + + @Override + public boolean isRequestHeadersAllowed() { + return false; + } + + @Override + public boolean isRequestBodyAllowed() { + return false; + } + + @Override + public int getSampleTitle() { + return R.string.title_request_params_debug; + } + + @Override + public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { + return getAsyncHttpClient().get(this, getDefaultURL(), getRequestParams(), getResponseHandler()); + } + + // TODO: allow parsing multiple values for each type, maybe like "type.key=value" ? + private RequestParams getRequestParams() { + RequestParams rp = new RequestParams(); + // contents of customParams custom field view + String customParamsText = customParams.getText().toString(); + String[] pairs = customParamsText.split("\n"); + // temp content holders + Map> mapOfMaps = new HashMap<>(); + Map> mapOfLists = new HashMap<>(); + Map mapOfArrays = new HashMap<>(); + Map> mapOfSets = new HashMap<>(); + for (String pair : pairs) { + String[] kv = pair.split("="); + if (kv.length != 2) + continue; + String key = kv[0].trim(); + String value = kv[1].trim(); + if ("array".equals(key)) { + String[] values = mapOfArrays.get(key); + if (values == null) { + values = new String[]{value}; + } else { + values = API8Util.copyOfRange(values, 0, values.length + 1); + values[values.length - 1] = value; + } + mapOfArrays.put(key, values); + } else if ("list".equals(key)) { + List values = mapOfLists.get(key); + if (values == null) { + values = new ArrayList<>(); + } + values.add(value); + mapOfLists.put(key, values); + } else if ("set".equals(key)) { + Set values = mapOfSets.get(key); + if (values == null) { + values = new HashSet<>(); + } + values.add(value); + mapOfSets.put(key, values); + } else if ("map".equals(key)) { + Map values = mapOfMaps.get(key); + if (values == null) { + values = new HashMap<>(); + } + values.put(key + values.size(), value); + mapOfMaps.put(key, values); + } + } + // fill in string list + for (Map.Entry> entry : mapOfLists.entrySet()) { + rp.put(entry.getKey(), entry.getValue()); + } + // fill in string array + for (Map.Entry entry : mapOfArrays.entrySet()) { + rp.put(entry.getKey(), entry.getValue()); + } + // fill in string set + for (Map.Entry> entry : mapOfSets.entrySet()) { + rp.put(entry.getKey(), entry.getValue()); + } + // fill in string map + for (Map.Entry> entry : mapOfMaps.entrySet()) { + rp.put(entry.getKey(), entry.getValue()); + } + // debug final URL construction into UI + debugResponse(LOG_TAG, rp.toString()); + return rp; + } +} diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java index 23ad87644..e65935200 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java @@ -25,6 +25,8 @@ import android.widget.ArrayAdapter; import android.widget.ListView; +import com.loopj.android.http.RequestParams; + import java.util.ArrayList; import java.util.List; @@ -58,7 +60,8 @@ public class WaypointsActivity extends ListActivity { new SampleConfig(R.string.title_content_type_http_entity, ContentTypeForHttpEntitySample.class), new SampleConfig(R.string.title_resume_download, ResumeDownloadSample.class), new SampleConfig(R.string.title_digest_auth, DigestAuthSample.class), - new SampleConfig(R.string.title_use_pool_thread, UsePoolThreadSample.class) + new SampleConfig(R.string.title_use_pool_thread, UsePoolThreadSample.class), + new SampleConfig(R.string.title_request_params_debug, RequestParamsDebug.class) }; @Override diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/API8Util.java b/sample/src/main/java/com/loopj/android/http/sample/util/API8Util.java new file mode 100644 index 000000000..5f7364f4f --- /dev/null +++ b/sample/src/main/java/com/loopj/android/http/sample/util/API8Util.java @@ -0,0 +1,23 @@ +package com.loopj.android.http.sample.util; + +import java.lang.reflect.Array; + +public class API8Util { + + @SuppressWarnings("unchecked") + public static T[] copyOfRange(T[] original, int start, int end) { + int originalLength = original.length; // For exception priority compatibility. + if (start > end) { + throw new IllegalArgumentException(); + } + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + int resultLength = end - start; + int copyLength = Math.min(resultLength, originalLength - start); + T[] result = (T[]) Array.newInstance(original.getClass().getComponentType(), resultLength); + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + +} diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 83bb24e4a..12bc817ac 100755 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -45,4 +45,5 @@ Resuming Download Digest Authentication Use Pool Thread in Response + Request Params debug From 9aaa6155d256e93f3f835d33d59f9649440f0f4d Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 16:29:41 +0200 Subject: [PATCH 079/167] Updated documentation on arrays on RequestParams, replaced for with foreach, better debugging of file arrays in toString(), #862 --- .../java/com/loopj/android/http/RequestParams.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 5fcb28d95..a67f81768 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -68,10 +68,10 @@ * List<String> list = new ArrayList<String>(); // Ordered collection * list.add("Java"); * list.add("C"); - * params.put("languages", list); // url params: "languages[]=Java&languages[]=C" + * params.put("languages", list); // url params: "languages[0]=Java&languages[1]=C" * * String[] colors = { "blue", "yellow" }; // Ordered collection - * params.put("colors", colors); // url params: "colors[]=blue&colors[]=yellow" + * params.put("colors", colors); // url params: "colors[0]=blue&colors[1]=yellow" * * File[] files = { new File("pic.jpg"), new File("pic1.jpg") }; // Ordered collection * params.put("files", files); // url params: "files[]=pic.jpg&files[]=pic1.jpg" @@ -228,11 +228,11 @@ public void put(String key, File files[], String contentType, String customFileN if (key != null) { List fileWrappers = new ArrayList(); - for (int i = 0; i < files.length; i++) { - if (files[i] == null || !files[i].exists()) { + for (File file : files) { + if (file == null || !file.exists()) { throw new FileNotFoundException(); } - fileWrappers.add(new FileWrapper(files[i], contentType, customFileName)); + fileWrappers.add(new FileWrapper(file, contentType, customFileName)); } fileArrayParams.put(key, fileWrappers); } @@ -460,7 +460,7 @@ public String toString() { result.append(entry.getKey()); result.append("="); - result.append("FILE"); + result.append("FILES(SIZE=").append(entry.getValue().size()).append(")"); } List params = getParamsList(null, urlParamsWithObjects); From 54a888c27bc0fe0e825e7932129e8141afce1462 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 16:52:16 +0200 Subject: [PATCH 080/167] Added 1.4.8 changelog, linked commits and issues for 1.4.7 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a3aeb5ff..99c0c17d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,21 @@ # CHANGELOG +## 1.4.8 (future release) + + - New constructor for BinaryHttpResponseHandler which takes Looper as argument (thanks to @ScottFrank) + - SaxAsyncHttpResponseHandler can be now provided with custom charset, instead of just using default one + - Library LogCat tags now use shorter form (forced through Lint checks), appendix "ResponseHandler" shortened to "RH" + - Updated documentation on `RequestHandle.cancel(boolean)` and returning correct response according to handle state + - SaxAsyncHttpResponseHandler onFailure(int, Header[], byte[], Throwable) used wrong fallback to onSuccess(int, Header[], T), fixed to onFailure(int, Header[], T), where T extends SAX DefaultHandler + - Regression fix on onProgress(int,int) documentation + - Sample application now can be built with LeakCanary, use i.e. `gradle :sample:installWithLeakCanaryDebug` to use it + - Updated RequestParams documentation on handling arrays, sets and maps, along with new RequestParamsDebug sample + ## 1.4.7 (released 9. 5. 2015) +Complete list of commits included is here [https://github.com/loopj/android-async-http/commits/1.4.7](https://github.com/loopj/android-async-http/commits/1.4.7) +List of closed issues is here [https://github.com/loopj/android-async-http/issues?milestone=6&state=closed](https://github.com/loopj/android-async-http/issues?milestone=6&state=closed) + - Fixed crash when canceling through RequestHandle from UI Thread (NetworkOnMainThreadException) - Fixed URL encoding feature, that was breaking whole URL, not just path and query parts - FileAsyncHttpResponseHandler now checks that target file path is available or can be created From f39b23f35aec071b813e610c4c734517937543f4 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 18:32:07 +0200 Subject: [PATCH 081/167] Allowing for FileAsyncHttpResponseHandler to be constructed with directory/folder path and file will be created automatically from URL --- .../http/FileAsyncHttpResponseHandler.java | 73 +++++++++++++++++-- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index af0fc218a..f80694927 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -33,6 +33,8 @@ public abstract class FileAsyncHttpResponseHandler extends AsyncHttpResponseHand protected final File file; protected final boolean append; + protected final boolean renameIfExists; + protected File frontendFile; private static final String LOG_TAG = "FileAsyncHttpRH"; /** @@ -51,14 +53,30 @@ public FileAsyncHttpResponseHandler(File file) { * @param append whether data should be appended to existing file */ public FileAsyncHttpResponseHandler(File file, boolean append) { + this(file, append, false); + } + + /** + * Obtains new FileAsyncHttpResponseHandler and stores response in passed file + * + * @param file File to store response within, must not be null + * @param append whether data should be appended to existing file + * @param renameTargetFileIfExists whether target file should be renamed if it already exists + */ + public FileAsyncHttpResponseHandler(File file, boolean append, boolean renameTargetFileIfExists) { super(); Utils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null"); - Utils.asserts(!file.isDirectory(), "File passed into FileAsyncHttpResponseHandler constructor must not point to directory"); - if (!file.getParentFile().isDirectory()) { + if (!file.isDirectory() && !file.getParentFile().isDirectory()) { Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location"); } + if (file.isDirectory()) { + if (!file.mkdirs()) { + Log.d(LOG_TAG, "Cannot create directories for requested Directory location, might not be a problem"); + } + } this.file = file; this.append = append; + this.renameIfExists = renameTargetFileIfExists; } /** @@ -70,6 +88,7 @@ public FileAsyncHttpResponseHandler(Context context) { super(); this.file = getTemporaryFile(context); this.append = false; + this.renameIfExists = false; } /** @@ -90,8 +109,6 @@ public boolean deleteTargetFile() { protected File getTemporaryFile(Context context) { Utils.asserts(context != null, "Tried creating temporary file without having Context"); try { - // not effective in release mode - assert context != null; return File.createTempFile("temp_", "_handled", context.getCacheDir()); } catch (IOException e) { Log.e(LOG_TAG, "Cannot create temporary file", e); @@ -102,13 +119,55 @@ protected File getTemporaryFile(Context context) { /** * Retrieves File object in which the response is stored * - * @return File file in which the response is stored + * @return File file in which the response was to be stored */ - protected File getTargetFile() { - assert (file != null); + protected File getOriginalFile() { + Utils.asserts(file != null, "Target file is null, fatal!"); return file; } + /** + * Retrieves File which represents response final location after possible renaming + * + * @return File final target file + */ + public File getTargetFile() { + if (frontendFile == null) { + frontendFile = getOriginalFile().isDirectory() ? getTargetFileByParsingURL() : getOriginalFile(); + } + return frontendFile; + } + + /** + * Will return File instance for file representing last URL segment in given folder. + * If file already exists and renameTargetFileIfExists was set as true, will try to find file + * which doesn't exist, naming template for such cases is "filename.ext" => "filename (%d).ext", + * or without extension "filename" => "filename (%d)" + */ + protected File getTargetFileByParsingURL() { + Utils.asserts(getOriginalFile().isDirectory(), "Target file is not a directory, cannot proceed"); + Utils.asserts(getRequestURI() != null, "RequestURI is null, cannot proceed"); + String requestURL = getRequestURI().toString(); + String filename = requestURL.substring(requestURL.lastIndexOf('/') + 1, requestURL.length()); + File targetFileRtn = new File(getOriginalFile(), filename); + if (targetFileRtn.exists() && renameIfExists) { + String format; + if (!filename.contains(".")) { + format = filename + " (%d)"; + } else { + format = filename.substring(0, filename.lastIndexOf('.')) + " (%d)" + filename.substring(filename.lastIndexOf('.'), filename.length()); + } + int index = 0; + while (true) { + targetFileRtn = new File(getOriginalFile(), String.format(format, index)); + if (!targetFileRtn.exists()) + return targetFileRtn; + index++; + } + } + return targetFileRtn; + } + @Override public final void onFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) { onFailure(statusCode, headers, throwable, getTargetFile()); From 5185f9d2dd0be99ff5d3dd696607ad967af40936 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 18:32:26 +0200 Subject: [PATCH 082/167] Added DirectorySample for new supported behavior of FileAsyncHttpResponseHandler --- sample/src/main/AndroidManifest.xml | 1 + .../android/http/sample/DirectorySample.java | 124 ++++++++++++++++++ .../http/sample/WaypointsActivity.java | 7 +- sample/src/main/res/values/strings.xml | 2 + 4 files changed, 130 insertions(+), 4 deletions(-) create mode 100755 sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index d2fa0094a..5ba56d9e6 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -29,6 +29,7 @@ + diff --git a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java new file mode 100755 index 000000000..706ad8f63 --- /dev/null +++ b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java @@ -0,0 +1,124 @@ +/* + Android Asynchronous Http Client Sample + Copyright (c) 2014 Marek Sebera + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.loopj.android.http.sample; + +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.FileAsyncHttpResponseHandler; +import com.loopj.android.http.RequestHandle; +import com.loopj.android.http.ResponseHandlerInterface; +import com.loopj.android.http.sample.util.FileUtil; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; + +import java.io.File; + +public class DirectorySample extends SampleParentActivity { + private static final String LOG_TAG = "DirectorySample"; + private FileAsyncHttpResponseHandler lastResponseHandler = null; + + @Override + public int getSampleTitle() { + return R.string.title_directory_sample; + } + + @Override + public boolean isRequestBodyAllowed() { + return false; + } + + @Override + public boolean isRequestHeadersAllowed() { + return true; + } + + @Override + public String getDefaultURL() { + return "https://httpbin.org/robots.txt"; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Button deleteTargetFile = new Button(this); + deleteTargetFile.setText(R.string.button_delete_target_file); + deleteTargetFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + clearOutputs(); + if (lastResponseHandler != null) { + File toBeDeleted = lastResponseHandler.getTargetFile(); + debugResponse(LOG_TAG, String.format("File was deleted? %b", toBeDeleted.delete())); + debugResponse(LOG_TAG, String.format("Delete file path: %s", toBeDeleted.getAbsolutePath())); + } else { + debugThrowable(LOG_TAG, new Error("You have to Run example first")); + } + } + }); + customFieldsLayout.addView(deleteTargetFile); + } + + @Override + public ResponseHandlerInterface getResponseHandler() { + lastResponseHandler = new FileAsyncHttpResponseHandler(getCacheDir(), false, true) { + @Override + public void onStart() { + clearOutputs(); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, File response) { + debugHeaders(LOG_TAG, headers); + debugStatusCode(LOG_TAG, statusCode); + debugFile(response); + } + + @Override + public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) { + debugHeaders(LOG_TAG, headers); + debugStatusCode(LOG_TAG, statusCode); + debugThrowable(LOG_TAG, throwable); + debugFile(file); + } + + private void debugFile(File file) { + if (file == null || !file.exists()) { + debugResponse(LOG_TAG, "Response is null"); + return; + } + try { + debugResponse(LOG_TAG, file.getAbsolutePath() + "\r\n\r\n" + FileUtil.getStringFromFile(file)); + } catch (Throwable t) { + Log.e(LOG_TAG, "Cannot debug file contents", t); + } + } + }; + return lastResponseHandler; + } + + @Override + public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { + return client.get(this, URL, headers, null, responseHandler); + } +} diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java index e65935200..0cccdfe3b 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java @@ -25,8 +25,6 @@ import android.widget.ArrayAdapter; import android.widget.ListView; -import com.loopj.android.http.RequestParams; - import java.util.ArrayList; import java.util.List; @@ -42,6 +40,7 @@ public class WaypointsActivity extends ListActivity { new SampleConfig(R.string.title_json_streamer_sample, JsonStreamerSample.class), new SampleConfig(R.string.title_sax_example, SaxSample.class), new SampleConfig(R.string.title_file_sample, FileSample.class), + new SampleConfig(R.string.title_directory_sample, DirectorySample.class), new SampleConfig(R.string.title_binary_sample, BinarySample.class), new SampleConfig(R.string.title_gzip_sample, GzipSample.class), new SampleConfig(R.string.title_redirect_302, Redirect302Sample.class), @@ -67,11 +66,11 @@ public class WaypointsActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, getTitlesList())); + setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, getTitlesList())); } private List getTitlesList() { - List titles = new ArrayList(); + List titles = new ArrayList<>(); for (SampleConfig config : samplesConfig) { titles.add(getString(config.titleId)); } diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 12bc817ac..11f28ca54 100755 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -8,6 +8,7 @@ Run Cancel + Delete original target file Use HTTPS Clear Outputs @@ -24,6 +25,7 @@ PATCH DELETE GET to File + GET to Directory GET binary data Cancel all requests SAX Example From 58efc20f5a20adaa972219a1777364649605394b Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 18:35:26 +0200 Subject: [PATCH 083/167] Fixed javadoc --- .../main/java/com/loopj/android/http/AsyncHttpRequest.java | 4 ++-- .../loopj/android/http/FileAsyncHttpResponseHandler.java | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index a54a0085c..9761473cf 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -56,7 +56,7 @@ public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriR * This method is called once by the system when the request is about to be * processed by the system. The library makes sure that a single request * is pre-processed only once. - *

+ *

 

* Please note: pre-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. @@ -71,7 +71,7 @@ public void onPreProcessRequest(AsyncHttpRequest request) { * This method is called once by the system when the request has been fully * sent, handled and finished. The library makes sure that a single request * is post-processed only once. - *

+ *

 

* Please note: post-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index f80694927..b066f80c5 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -141,8 +141,10 @@ public File getTargetFile() { /** * Will return File instance for file representing last URL segment in given folder. * If file already exists and renameTargetFileIfExists was set as true, will try to find file - * which doesn't exist, naming template for such cases is "filename.ext" => "filename (%d).ext", - * or without extension "filename" => "filename (%d)" + * which doesn't exist, naming template for such cases is "filename.ext" => "filename (%d).ext", + * or without extension "filename" => "filename (%d)" + * + * @return File in given directory constructed by last segment of request URL */ protected File getTargetFileByParsingURL() { Utils.asserts(getOriginalFile().isDirectory(), "Target file is not a directory, cannot proceed"); From fc0f3c4efd1246a615ba8cd545c3700231c73145 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sun, 12 Jul 2015 18:36:32 +0200 Subject: [PATCH 084/167] Updated Gradle Wrapper and configured Travis CI to check javadocs syntax on build --- .travis.yml | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 52266 -> 52271 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 01d25146e..ff2abb9d3 100755 --- a/.travis.yml +++ b/.travis.yml @@ -13,3 +13,4 @@ script: - echo "nexusUsername=dummy" >> library/gradle.properties - echo "nexusPassword=dummy" >> library/gradle.properties - ./gradlew clean assemble check + - ./gradlew :library:androidJavadocs diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b5166dad4d90021f6a0b45268c0755719f1d5cd4..30d399d8d2bf522ff5de94bf434a7cc43a9a74b5 100644 GIT binary patch delta 1828 zcmZuxdrXs86u=}&0Yh0A9D^~V27JID zgX;{{3W{tH4OpPEg#wnASHbGkF|GkgT*h-m3h+qI01o6# zGT1JlKBj;;;P5*T`Md@o+P(Omj=;#~HL=X7yPO9M-}?)eIpOn;6EJ^?HqHklZn+!l zvpKZf1(-?YG;7?9OPm!_nH>U8NX;S`ZrNdq|u1;OMX@g2VC9|pJ`XssDpje?- zgryYh5zJG|74p#AGU@P@cvWyOlAwRUQ%7SO}*5%Gts05`m${Z zp+z_#O}y8*iz{}&JN>Tz8Qy*|Pt_S)bz)u465)xEA2^bU^^a$CJ4%e&lRs)7<{kef z$5wlM*#-B%gYIh;4<{dF@ib+N1i3j4pPNhlzSmtZs_@QeP|8G6N7tqDkHl+|qpRzO z>h6C~84_6(enWX=>NI+d+oyE)&p;hB2;+LgkwEuxj5?60^vzVJeAZmTY*{3q$D zN7qMZYKNZ~4-BR&f_;TYS0yGleT5RvEp)Nm@;FuYG+VzX_c<@Rz*tl;wksxmn8Sh#g5m-O4N+Iom$3_O;82Z+9m=RmX%WZhwnww;&*SFzb5J{Y;XMO-i{ zH4&^aTzH)a%&C$mtn+`q+bDf!F zY1KEL5T`xaoCSpq%`M}8Lg%%4Ss+|fUg zUbw(4WPS}?Wu`f6akKd?I8B*p>T)`6)h)qti>DuxXk(P~>rF&u+7Y4Eb0P>C_H|}} zW4T2Fv3d(lb!7oHWsw3!_t8|-PTadQ1kd!l0aZ*WWj1(q_DP}4#d+SXHj?2c$*|Hc zLnh|*M?+YAKTYk|Kv<7Ph|@>hpg8|xYiczQA*}$R0J~6AAxXO!Pxbpiyz2l>9V?kF z&JmB5EMPR?>LYT6OL1hQKh_U;Kt&aiVIO`*2J6a2XqBC89-bVCgRo_TG_~d+DCQ5Y z0O~ZM?j0tSKb{z5m0mmzghK3;YVd-gC}<+)>ic)AN&h<1h`mo`-E75fxPHh3oQnc} zPR?{7e{8M@Mc4`MuE#BAUwm&!4#oIcX-e8i+6sO#dqM@Dog0G5>JQyY9Ae#kNw?Xg zhCn+>G3E@1gWBq0n%dU_q1`R?(xikJ4~bb4j3Ttmz-EZVn|2cYZTMDO1Qrgm!xoIt yRE+_*8bashpHHYiJBYLt%fET;6=`_yMDlI&71>Fbb>iAiG4{IT?&xe}ZvF+r(~xTb delta 1820 zcmZvb3rv$&6vr>$*V4k;6;Kqcj+e?yp(3(JMMN?(XnDv>6p*Q7Wf?DP*i4iWQMa)v z2v;V{a7qzzD6jxylNKqDQeHDtr%MI|$qi#9Ksj z;(b511TwN^ng#CMExogFDVS}P;^E9(pejY8}J20i`JY5zuG+L&t)!ft-_YcM-cs;iR zp~T+(x?r%MSlgQ+WQVYXROnrKk)RrLC$9Jz+o8>3q-n@Y55oo!OO8{ek`) z+2DRd=5<3=YRQ9RvqdYSu1=0g9L@}jbyLBqPLirgnR@i0#aP*-^7a->$6HS}#9Q8f z_D|>!t9I~zclj;vc+IjuUJ4LPp9mJto2(W)C9Y$MHbf?V%5VW5*gX!wnEVVtL(krE z8hn?6&0tEQau7n0p6S3sP^gyE;K%G+d>|EvW@z&HoZA8*2an&NMES{OYB-aB$p)q> z%N|qm<+-~wIIL;n!PKTImO9I;AJHkVnk4E|P#Z{dZr1-qNo8XU&6#b&tOa+N;*FzK zZ{pJCfPh8U!zJi{u1A8&r7&Zbvh!~T+i8909}kYvzQJ8rT%`2|?a=yx&T6-S`s>0$ z3v`*B7Po}KFtQ~c^m5B?P|-CyR$WVgvEf=Ms7>p3(05xEppC6GPoj^8af&_`v_(&S z#clgwe4tHfG5}<4-zVb;qYM7L!xdWAT?z9kBHuYmzTZ{kkJ~UwI&^&%E5IxZdltzYkRw-W~q3rD+CtileVKNlq`%# z78Yz$wi$;TW5N1(W#e*{4MJTWi>)W}Ne|BWo)Ml6o-s<9k}_P_=Y|8i?O_24-BKq1 z++3&TxV+nru8ZI_4LKoud_lANg;T<3b+$Uvl_TkDok>?~aA1!dEOL9KjA!+{v!TZs z@C3oH)DXN9U)4w?i_RYh_DY$LYN1MBE5&8KbW<)9++L4I>g6x=vfef|Pe6Ln@(}Vd z>7@jF^##H%1~&<({aJ*1EfA8M Date: Sun, 12 Jul 2015 18:42:16 +0200 Subject: [PATCH 085/167] Extended DirectorySample with CheckBoxes to set constructor params --- .../loopj/android/http/sample/DirectorySample.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java index 706ad8f63..0ee8a87d4 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java @@ -22,6 +22,7 @@ import android.util.Log; import android.view.View; import android.widget.Button; +import android.widget.CheckBox; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.FileAsyncHttpResponseHandler; @@ -37,6 +38,7 @@ public class DirectorySample extends SampleParentActivity { private static final String LOG_TAG = "DirectorySample"; private FileAsyncHttpResponseHandler lastResponseHandler = null; + private CheckBox cbAppend, cbRename; @Override public int getSampleTitle() { @@ -76,12 +78,20 @@ public void onClick(View v) { } } }); + cbAppend = new CheckBox(this); + cbAppend.setText("Constructor \"append\" is true?"); + cbAppend.setChecked(false); + cbRename = new CheckBox(this); + cbRename.setText("Constructor \"renameTargetFileIfExists\" is true?"); + cbRename.setChecked(true); customFieldsLayout.addView(deleteTargetFile); + customFieldsLayout.addView(cbAppend); + customFieldsLayout.addView(cbRename); } @Override public ResponseHandlerInterface getResponseHandler() { - lastResponseHandler = new FileAsyncHttpResponseHandler(getCacheDir(), false, true) { + lastResponseHandler = new FileAsyncHttpResponseHandler(getCacheDir(), cbAppend.isChecked(), cbRename.isChecked()) { @Override public void onStart() { clearOutputs(); From af9a1f5e9b708bfddd6b834f63a3342899847868 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 18:55:30 +0200 Subject: [PATCH 086/167] Added BlackholeHttpResponseHandler for when you want to ignore response to your request, #416 --- CHANGELOG.md | 1 + .../http/BlackholeHttpResponseHandler.java | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 99c0c17d2..331e439bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Regression fix on onProgress(int,int) documentation - Sample application now can be built with LeakCanary, use i.e. `gradle :sample:installWithLeakCanaryDebug` to use it - Updated RequestParams documentation on handling arrays, sets and maps, along with new RequestParamsDebug sample + - Added BlackholeHttpResponseHandler implementation, which discards all response contents and silents all various log messages (see #416) ## 1.4.7 (released 9. 5. 2015) diff --git a/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java new file mode 100644 index 000000000..8ff6bcddd --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java @@ -0,0 +1,64 @@ +package com.loopj.android.http; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; + +/** + * Blank implementation of ResponseHandlerInterface, which ignores all contents returned by + * remote HTTP endpoint, and discards all various log messages + *

 

+ * Use this implementation, if you deliberately want to ignore all response, because you cannot + * pass null ResponseHandlerInterface into AsyncHttpClient implementation + */ +public class BlackholeHttpResponseHandler extends AsyncHttpResponseHandler { + + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + + } + + @Override + public void onProgress(long bytesWritten, long totalSize) { + + } + + @Override + public void onCancel() { + + } + + @Override + public void onFinish() { + + } + + @Override + public void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response) { + + } + + @Override + public void onPreProcessResponse(ResponseHandlerInterface instance, HttpResponse response) { + + } + + @Override + public void onRetry(int retryNo) { + + } + + @Override + public void onStart() { + + } + + @Override + public void onUserException(Throwable error) { + + } +} From 9164374f8e25f7d1103f2ac9e66f27ea8e5c0e95 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 22:28:01 +0200 Subject: [PATCH 087/167] Added LogInterface and default used implementation LogHandler, which wrap logging enabled status and verbosity level --- .../loopj/android/http/AsyncHttpClient.java | 87 ++++++++++-- .../loopj/android/http/AsyncHttpRequest.java | 4 +- .../http/AsyncHttpResponseHandler.java | 20 +-- .../http/BaseJsonHttpResponseHandler.java | 4 +- .../http/BinaryHttpResponseHandler.java | 6 +- .../http/DataAsyncHttpResponseHandler.java | 6 +- .../http/FileAsyncHttpResponseHandler.java | 4 +- .../android/http/JsonHttpResponseHandler.java | 14 +- .../android/http/JsonStreamerEntity.java | 2 +- .../com/loopj/android/http/LogHandler.java | 134 ++++++++++++++++++ .../com/loopj/android/http/LogInterface.java | 51 +++++++ .../android/http/PersistentCookieStore.java | 6 +- .../RangeFileAsyncHttpResponseHandler.java | 2 +- .../com/loopj/android/http/RequestParams.java | 4 +- .../http/SaxAsyncHttpResponseHandler.java | 4 +- .../android/http/SimpleMultipartEntity.java | 4 +- .../android/http/TextHttpResponseHandler.java | 2 +- .../http/sample/JsonStreamerSample.java | 2 +- 18 files changed, 302 insertions(+), 54 deletions(-) create mode 100644 library/src/main/java/com/loopj/android/http/LogHandler.java create mode 100644 library/src/main/java/com/loopj/android/http/LogInterface.java diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 6684c6f40..df06d9209 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -141,6 +141,8 @@ public class AsyncHttpClient { private final Map clientHeaderMap; private boolean isUrlEncodingEnabled = true; + public static LogInterface log = new LogHandler(); + /** * Creates a new AsyncHttpClient with default constructor arguments values */ @@ -187,17 +189,17 @@ public AsyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int htt */ private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) { if (fixNoHttpResponseException) { - Log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates."); + log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates."); } if (httpPort < 1) { httpPort = 80; - Log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80"); + log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80"); } if (httpsPort < 1) { httpsPort = 443; - Log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443"); + log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443"); } // Fix to SSL flaw in API < ICS @@ -254,7 +256,7 @@ public void process(HttpRequest request, HttpContext context) { for (String header : clientHeaderMap.keySet()) { if (request.containsHeader(header)) { Header overwritten = request.getFirstHeader(header); - Log.d(LOG_TAG, + log.d(LOG_TAG, String.format("Headers were overwritten! (%s | %s) overwrites (%s | %s)", header, clientHeaderMap.get(header), overwritten.getName(), overwritten.getValue()) @@ -342,6 +344,67 @@ public HttpContext getHttpContext() { return this.httpContext; } + /** + * Will set logging enabled flag on underlying LogInterface instance. + * Default setting is logging enabled. + * + * @param loggingEnabled whether the logging should be enabled or not + */ + public void setLoggingEnabled(boolean loggingEnabled) { + log.setLoggingEnabled(loggingEnabled); + } + + /** + * Returns logging enabled flag from underlying LogInterface instance + * Default setting is logging enabled. + * + * @return boolean whether is logging across the library currently enabled + */ + public boolean isLoggingEnabled() { + return log.isLoggingEnabled(); + } + + /** + * Sets log level to be used across all library default implementation + * Default setting is VERBOSE log level. + * + * @param logLevel int log level, either from LogInterface interface or from {@link android.util.Log} + */ + public void setLoggingLevel(int logLevel) { + log.setLoggingLevel(logLevel); + } + + /** + * Retrieves current log level from underlying LogInterface instance. + * Default setting is VERBOSE log level. + * + * @return int log level currently in effect + */ + public int getLoggingLevel() { + return log.getLoggingLevel(); + } + + /** + * Will return current LogInterface used in AsyncHttpClient instance + * + * @return LogInterface currently used by AsyncHttpClient instance + */ + public LogInterface getLogInterface() { + return log; + } + + /** + * Sets default LogInterface (similar to std Android Log util class) instance, + * to be used in AsyncHttpClient instance + * + * @param logInterfaceInstance LogInterface instance, if null, nothing is done + */ + public void setLogInterface(LogInterface logInterfaceInstance) { + if (logInterfaceInstance != null) { + log = logInterfaceInstance; + } + } + /** * Sets an optional CookieStore to use when making requests * @@ -669,7 +732,7 @@ public void setBasicAuth(String username, String password, AuthScope scope, bool public void setCredentials(AuthScope authScope, Credentials credentials) { if (credentials == null) { - Log.d(LOG_TAG, "Provided credentials are null, not setting"); + log.d(LOG_TAG, "Provided credentials are null, not setting"); return; } this.httpClient.getCredentialsProvider().setCredentials(authScope == null ? AuthScope.ANY : authScope, credentials); @@ -718,7 +781,7 @@ public void clearCredentialsProvider() { */ public void cancelRequests(final Context context, final boolean mayInterruptIfRunning) { if (context == null) { - Log.e(LOG_TAG, "Passed null Context to cancelRequests"); + log.e(LOG_TAG, "Passed null Context to cancelRequests"); return; } @@ -1304,10 +1367,10 @@ protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpCo if (responseHandler.getUseSynchronousMode() && !responseHandler.getUsePoolThread()) { throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead."); } - + if (contentType != null) { if (uriRequest instanceof HttpEntityEnclosingRequestBase && ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != null && uriRequest.containsHeader(HEADER_CONTENT_TYPE)) { - Log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type"); + log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type"); } else { uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType); } @@ -1384,7 +1447,7 @@ public static String getUrlWithQueryString(boolean shouldEncodeUrl, String url, url = _uri.toASCIIString(); } catch (Exception ex) { // Should not really happen, added just for sake of validity - Log.e(LOG_TAG, "getUrlWithQueryString encoding URL", ex); + log.e(LOG_TAG, "getUrlWithQueryString encoding URL", ex); } } @@ -1433,7 +1496,7 @@ public static void silentCloseInputStream(InputStream is) { is.close(); } } catch (IOException e) { - Log.w(LOG_TAG, "Cannot close input stream", e); + log.w(LOG_TAG, "Cannot close input stream", e); } } @@ -1448,7 +1511,7 @@ public static void silentCloseOutputStream(OutputStream os) { os.close(); } } catch (IOException e) { - Log.w(LOG_TAG, "Cannot close output stream", e); + log.w(LOG_TAG, "Cannot close output stream", e); } } @@ -1521,7 +1584,7 @@ public static void endEntityViaReflection(HttpEntity entity) { } } } catch (Throwable t) { - Log.e(LOG_TAG, "wrappedEntity consume", t); + log.e(LOG_TAG, "wrappedEntity consume", t); } } } diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index 9761473cf..451a4719e 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -110,7 +110,7 @@ public void run() { if (!isCancelled()) { responseHandler.sendFailureMessage(0, null, null, e); } else { - Log.e("AsyncHttpRequest", "makeRequestWithRetries returned error", e); + AsyncHttpClient.log.e("AsyncHttpRequest", "makeRequestWithRetries returned error", e); } } @@ -204,7 +204,7 @@ private void makeRequestWithRetries() throws IOException { } } catch (Exception e) { // catch anything else to ensure failure message is propagated - Log.e("AsyncHttpRequest", "Unhandled exception origin cause", e); + AsyncHttpClient.log.e("AsyncHttpRequest", "Unhandled exception origin cause", e); cause = new IOException("Unhandled exception: " + e.getMessage()); } diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 71ada3c84..625512bd8 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -195,7 +195,7 @@ public void setUseSynchronousMode(boolean sync) { // A looper must be prepared before setting asynchronous mode. if (!sync && looper == null) { sync = true; - Log.w(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode."); + AsyncHttpClient.log.w(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode."); } // If using asynchronous mode. @@ -248,7 +248,7 @@ public String getCharset() { * @param totalSize total size of file */ public void onProgress(long bytesWritten, long totalSize) { - Log.v(LOG_TAG, String.format("Progress %d from %d (%2.0f%%)", bytesWritten, totalSize, (totalSize > 0) ? (bytesWritten * 1.0 / totalSize) * 100 : -1)); + AsyncHttpClient.log.v(LOG_TAG, String.format("Progress %d from %d (%2.0f%%)", bytesWritten, totalSize, (totalSize > 0) ? (bytesWritten * 1.0 / totalSize) * 100 : -1)); } /** @@ -301,15 +301,15 @@ public void onPostProcessResponse(ResponseHandlerInterface instance, HttpRespons * @param retryNo number of retry */ public void onRetry(int retryNo) { - Log.d(LOG_TAG, String.format("Request retry no. %d", retryNo)); + AsyncHttpClient.log.d(LOG_TAG, String.format("Request retry no. %d", retryNo)); } public void onCancel() { - Log.d(LOG_TAG, "Request got cancelled"); + AsyncHttpClient.log.d(LOG_TAG, "Request got cancelled"); } public void onUserException(Throwable error) { - Log.e(LOG_TAG, "User-space exception detected!", error); + AsyncHttpClient.log.e(LOG_TAG, "User-space exception detected!", error); throw new RuntimeException(error); } @@ -359,7 +359,7 @@ protected void handleMessage(Message message) { if (response != null && response.length >= 3) { onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]); } else { - Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params"); + AsyncHttpClient.log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params"); } break; case FAILURE_MESSAGE: @@ -367,7 +367,7 @@ protected void handleMessage(Message message) { if (response != null && response.length >= 4) { onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]); } else { - Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params"); + AsyncHttpClient.log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params"); } break; case START_MESSAGE: @@ -382,10 +382,10 @@ protected void handleMessage(Message message) { try { onProgress((Long) response[0], (Long) response[1]); } catch (Throwable t) { - Log.e(LOG_TAG, "custom onProgress contains an error", t); + AsyncHttpClient.log.e(LOG_TAG, "custom onProgress contains an error", t); } } else { - Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params"); + AsyncHttpClient.log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params"); } break; case RETRY_MESSAGE: @@ -393,7 +393,7 @@ protected void handleMessage(Message message) { if (response != null && response.length == 1) { onRetry((Integer) response[0]); } else { - Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params"); + AsyncHttpClient.log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params"); } break; case CANCEL_MESSAGE: diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java index e5d5599d0..21f9f59a7 100755 --- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java @@ -87,7 +87,7 @@ public void run() { } }); } catch (final Throwable t) { - Log.d(LOG_TAG, "parseResponse thrown an problem", t); + AsyncHttpClient.log.d(LOG_TAG, "parseResponse thrown an problem", t); postRunnable(new Runnable() { @Override public void run() { @@ -123,7 +123,7 @@ public void run() { } }); } catch (Throwable t) { - Log.d(LOG_TAG, "parseResponse thrown an problem", t); + AsyncHttpClient.log.d(LOG_TAG, "parseResponse thrown an problem", t); postRunnable(new Runnable() { @Override public void run() { diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index 6cde969db..68e7076d2 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -89,7 +89,7 @@ public BinaryHttpResponseHandler(String[] allowedContentTypes) { if (allowedContentTypes != null) { mAllowedContentTypes = allowedContentTypes; } else { - Log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); + AsyncHttpClient.log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); } } @@ -105,7 +105,7 @@ public BinaryHttpResponseHandler(String[] allowedContentTypes, Looper looper) { if (allowedContentTypes != null) { mAllowedContentTypes = allowedContentTypes; } else { - Log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); + AsyncHttpClient.log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); } } @@ -140,7 +140,7 @@ public final void sendResponseMessage(HttpResponse response) throws IOException foundAllowedContentType = true; } } catch (PatternSyntaxException e) { - Log.e(LOG_TAG, "Given pattern is not valid: " + anAllowedContentType, e); + AsyncHttpClient.log.e(LOG_TAG, "Given pattern is not valid: " + anAllowedContentType, e); } } if (!foundAllowedContentType) { diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index 8b8bfbb63..7f1360ec7 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -46,7 +46,7 @@ public DataAsyncHttpResponseHandler() { * @param responseBody response body received so far */ public void onProgressData(byte[] responseBody) { - Log.d(LOG_TAG, "onProgressData(byte[]) was not overriden, but callback was received"); + AsyncHttpClient.log.d(LOG_TAG, "onProgressData(byte[]) was not overriden, but callback was received"); } @@ -67,10 +67,10 @@ protected void handleMessage(Message message) { try { onProgressData((byte[]) response[0]); } catch (Throwable t) { - Log.e(LOG_TAG, "custom onProgressData contains an error", t); + AsyncHttpClient.log.e(LOG_TAG, "custom onProgressData contains an error", t); } } else { - Log.e(LOG_TAG, "PROGRESS_DATA_MESSAGE didn't got enough params"); + AsyncHttpClient.log.e(LOG_TAG, "PROGRESS_DATA_MESSAGE didn't got enough params"); } break; } diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index b066f80c5..23e043e33 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -71,7 +71,7 @@ public FileAsyncHttpResponseHandler(File file, boolean append, boolean renameTar } if (file.isDirectory()) { if (!file.mkdirs()) { - Log.d(LOG_TAG, "Cannot create directories for requested Directory location, might not be a problem"); + AsyncHttpClient.log.d(LOG_TAG, "Cannot create directories for requested Directory location, might not be a problem"); } } this.file = file; @@ -111,7 +111,7 @@ protected File getTemporaryFile(Context context) { try { return File.createTempFile("temp_", "_handled", context.getCacheDir()); } catch (IOException e) { - Log.e(LOG_TAG, "Cannot create temporary file", e); + AsyncHttpClient.log.e(LOG_TAG, "Cannot create temporary file", e); } return null; } diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index 33b827a4f..84ded1791 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -87,7 +87,7 @@ public JsonHttpResponseHandler(String encoding, boolean useRFC5179CompatibilityM * @param response parsed response if any */ public void onSuccess(int statusCode, Header[] headers, JSONObject response) { - Log.w(LOG_TAG, "onSuccess(int, Header[], JSONObject) was not overriden, but callback was received"); + AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], JSONObject) was not overriden, but callback was received"); } /** @@ -98,7 +98,7 @@ public void onSuccess(int statusCode, Header[] headers, JSONObject response) { * @param response parsed response if any */ public void onSuccess(int statusCode, Header[] headers, JSONArray response) { - Log.w(LOG_TAG, "onSuccess(int, Header[], JSONArray) was not overriden, but callback was received"); + AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], JSONArray) was not overriden, but callback was received"); } /** @@ -110,7 +110,7 @@ public void onSuccess(int statusCode, Header[] headers, JSONArray response) { * @param errorResponse parsed response if any */ public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) { - Log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONObject) was not overriden, but callback was received", throwable); + AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONObject) was not overriden, but callback was received", throwable); } /** @@ -122,17 +122,17 @@ public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSO * @param errorResponse parsed response if any */ public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) { - Log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONArray) was not overriden, but callback was received", throwable); + AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONArray) was not overriden, but callback was received", throwable); } @Override public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { - Log.w(LOG_TAG, "onFailure(int, Header[], String, Throwable) was not overriden, but callback was received", throwable); + AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], String, Throwable) was not overriden, but callback was received", throwable); } @Override public void onSuccess(int statusCode, Header[] headers, String responseString) { - Log.w(LOG_TAG, "onSuccess(int, Header[], String) was not overriden, but callback was received"); + AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], String) was not overriden, but callback was received"); } @Override @@ -230,7 +230,7 @@ public void run() { parser.run(); } } else { - Log.v(LOG_TAG, "response body is null, calling onFailure(Throwable, JSONObject)"); + AsyncHttpClient.log.v(LOG_TAG, "response body is null, calling onFailure(Throwable, JSONObject)"); onFailure(statusCode, headers, throwable, (JSONObject) null); } } diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index 5bc2761ce..51cb4f9b0 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -236,7 +236,7 @@ public void writeTo(final OutputStream out) throws IOException { os.write((elapsedTime + "").getBytes()); } - Log.i(LOG_TAG, "Uploaded JSON in " + Math.floor(elapsedTime / 1000) + " seconds"); + AsyncHttpClient.log.i(LOG_TAG, "Uploaded JSON in " + Math.floor(elapsedTime / 1000) + " seconds"); } // Close the JSON object. diff --git a/library/src/main/java/com/loopj/android/http/LogHandler.java b/library/src/main/java/com/loopj/android/http/LogHandler.java new file mode 100644 index 000000000..dc7ffd2bc --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/LogHandler.java @@ -0,0 +1,134 @@ +package com.loopj.android.http; + +import android.annotation.TargetApi; +import android.os.Build; +import android.util.Log; + +public class LogHandler implements LogInterface { + + boolean mLoggingEnabled = true; + int mLoggingLevel = VERBOSE; + + @Override + public boolean isLoggingEnabled() { + return mLoggingEnabled; + } + + @Override + public void setLoggingEnabled(boolean loggingEnabled) { + this.mLoggingEnabled = loggingEnabled; + } + + @Override + public int getLoggingLevel() { + return mLoggingLevel; + } + + @Override + public void setLoggingLevel(int loggingLevel) { + this.mLoggingLevel = loggingLevel; + } + + @Override + public boolean shouldLog(int logLevel) { + return logLevel >= mLoggingLevel; + } + + public void log(int logLevel, String tag, String msg) { + logWithThrowable(logLevel, tag, msg, null); + } + + public void logWithThrowable(int logLevel, String tag, String msg, Throwable t) { + if (isLoggingEnabled() && shouldLog(logLevel)) { + switch (logLevel) { + case VERBOSE: + Log.v(tag, msg, t); + break; + case WARN: + Log.w(tag, msg, t); + break; + case ERROR: + Log.e(tag, msg, t); + break; + case DEBUG: + Log.d(tag, msg, t); + break; + case WTF: + if (Integer.valueOf(Build.VERSION.SDK) > 8) { + checkedWtf(tag, msg, t); + } else { + Log.e(tag, msg, t); + } + break; + case INFO: + Log.i(tag, msg, t); + break; + } + } + } + + @TargetApi(Build.VERSION_CODES.FROYO) + private void checkedWtf(String tag, String msg, Throwable t) { + Log.wtf(tag, msg, t); + } + + @Override + public void v(String tag, String msg) { + log(VERBOSE, tag, msg); + } + + @Override + public void v(String tag, String msg, Throwable t) { + logWithThrowable(VERBOSE, tag, msg, t); + } + + @Override + public void d(String tag, String msg) { + log(VERBOSE, tag, msg); + } + + @Override + public void d(String tag, String msg, Throwable t) { + logWithThrowable(DEBUG, tag, msg, t); + } + + @Override + public void i(String tag, String msg) { + log(INFO, tag, msg); + } + + @Override + public void i(String tag, String msg, Throwable t) { + logWithThrowable(INFO, tag, msg, t); + } + + @Override + public void w(String tag, String msg) { + log(WARN, tag, msg); + } + + @Override + public void w(String tag, String msg, Throwable t) { + logWithThrowable(WARN, tag, msg, t); + } + + @Override + public void e(String tag, String msg) { + log(ERROR, tag, msg); + } + + @Override + public void e(String tag, String msg, Throwable t) { + logWithThrowable(ERROR, tag, msg, t); + } + + @Override + public void wtf(String tag, String msg) { + log(WTF, tag, msg); + } + + @Override + public void wtf(String tag, String msg, Throwable t) { + logWithThrowable(WTF, tag, msg, t); + } +} diff --git a/library/src/main/java/com/loopj/android/http/LogInterface.java b/library/src/main/java/com/loopj/android/http/LogInterface.java new file mode 100644 index 000000000..f5a06b19a --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/LogInterface.java @@ -0,0 +1,51 @@ +package com.loopj.android.http; + +/** + * Interface independent to any library, which currently uses same interface as {@link android.util.Log} implementation + * You can change currently used LogInterface through {@link AsyncHttpClient#setLogInterface(LogInterface)} + */ +public interface LogInterface { + + int VERBOSE = 2; + int DEBUG = 3; + int INFO = 4; + int WARN = 5; + int ERROR = 6; + int WTF = 8; + + boolean isLoggingEnabled(); + + void setLoggingEnabled(boolean loggingEnabled); + + int getLoggingLevel(); + + void setLoggingLevel(int loggingLevel); + + boolean shouldLog(int logLevel); + + void v(String tag, String msg); + + void v(String tag, String msg, Throwable t); + + void d(String tag, String msg); + + void d(String tag, String msg, Throwable t); + + void i(String tag, String msg); + + void i(String tag, String msg, Throwable t); + + void w(String tag, String msg); + + void w(String tag, String msg, Throwable t); + + void e(String tag, String msg); + + void e(String tag, String msg, Throwable t); + + void wtf(String tag, String msg); + + void wtf(String tag, String msg, Throwable t); + + +} diff --git a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java index e5e99c8c8..c35027137 100755 --- a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java +++ b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java @@ -187,7 +187,7 @@ protected String encodeCookie(SerializableCookie cookie) { ObjectOutputStream outputStream = new ObjectOutputStream(os); outputStream.writeObject(cookie); } catch (IOException e) { - Log.d(LOG_TAG, "IOException in encodeCookie", e); + AsyncHttpClient.log.d(LOG_TAG, "IOException in encodeCookie", e); return null; } @@ -208,9 +208,9 @@ protected Cookie decodeCookie(String cookieString) { ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); cookie = ((SerializableCookie) objectInputStream.readObject()).getCookie(); } catch (IOException e) { - Log.d(LOG_TAG, "IOException in decodeCookie", e); + AsyncHttpClient.log.d(LOG_TAG, "IOException in decodeCookie", e); } catch (ClassNotFoundException e) { - Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e); + AsyncHttpClient.log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e); } return cookie; diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index fd96e4d17..038fe6489 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -67,7 +67,7 @@ public void sendResponseMessage(HttpResponse response) throws IOException { append = false; current = 0; } else { - Log.v(LOG_TAG, AsyncHttpClient.HEADER_CONTENT_RANGE + ": " + header.getValue()); + AsyncHttpClient.log.v(LOG_TAG, AsyncHttpClient.HEADER_CONTENT_RANGE + ": " + header.getValue()); } sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), getResponseData(response.getEntity())); } diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index a67f81768..9377ede3e 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -123,7 +123,7 @@ public void setContentEncoding(final String encoding) { if (encoding != null) { this.contentEncoding = encoding; } else { - Log.d(LOG_TAG, "setContentEncoding called with null attribute"); + AsyncHttpClient.log.d(LOG_TAG, "setContentEncoding called with null attribute"); } } @@ -567,7 +567,7 @@ private HttpEntity createFormEntity() { try { return new UrlEncodedFormEntity(getParamsList(), contentEncoding); } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, "createFormEntity failed", e); + AsyncHttpClient.log.e(LOG_TAG, "createFormEntity failed", e); return null; // Can happen, if the 'contentEncoding' won't be HTTP.UTF_8 } } diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index 07ae057d2..1da440eeb 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -102,9 +102,9 @@ protected byte[] getResponseData(HttpEntity entity) throws IOException { inputStreamReader = new InputStreamReader(instream, getCharset()); rssReader.parse(new InputSource(inputStreamReader)); } catch (SAXException e) { - Log.e(LOG_TAG, "getResponseData exception", e); + AsyncHttpClient.log.e(LOG_TAG, "getResponseData exception", e); } catch (ParserConfigurationException e) { - Log.e(LOG_TAG, "getResponseData exception", e); + AsyncHttpClient.log.e(LOG_TAG, "getResponseData exception", e); } finally { AsyncHttpClient.silentCloseInputStream(instream); if (inputStreamReader != null) { diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index 42a2524b7..4ee81b6d8 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -97,7 +97,7 @@ public void addPart(String key, String value, String contentType) { out.write(CR_LF); } catch (final IOException e) { // Shall not happen on ByteArrayOutputStream - Log.e(LOG_TAG, "addPart ByteArrayOutputStream exception", e); + AsyncHttpClient.log.e(LOG_TAG, "addPart ByteArrayOutputStream exception", e); } } @@ -197,7 +197,7 @@ private byte[] createHeader(String key, String filename, String type) { headerStream.write(CR_LF); } catch (IOException e) { // Can't happen on ByteArrayOutputStream - Log.e(LOG_TAG, "createHeader ByteArrayOutputStream exception", e); + AsyncHttpClient.log.e(LOG_TAG, "createHeader ByteArrayOutputStream exception", e); } return headerStream.toByteArray(); } diff --git a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java index e755101d5..a9ea55bf5 100755 --- a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java @@ -120,7 +120,7 @@ public static String getResponseString(byte[] stringBytes, String charset) { } return toReturn; } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, "Encoding response into string failed", e); + AsyncHttpClient.log.e(LOG_TAG, "Encoding response into string failed", e); return null; } } diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java index c8044ac2e..295174761 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java @@ -88,7 +88,7 @@ public boolean isRequestHeadersAllowed() { protected JSONObject getBodyTextAsJSON() { String bodyText = getBodyText(); - if (bodyText != null && TextUtils.isEmpty(bodyText)) { + if (bodyText != null && !TextUtils.isEmpty(bodyText)) { try { return new JSONObject(bodyText); } catch (JSONException e) { From 908e251a3a21732eb83a4e460bfdc3e4268fe701 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 22:47:29 +0200 Subject: [PATCH 088/167] Added LogInterface usage into Sample application as an example --- CHANGELOG.md | 1 + .../http/sample/Redirect302Sample.java | 22 ++++++---- .../http/sample/SampleParentActivity.java | 41 +++++++++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 331e439bf..a85df1098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Sample application now can be built with LeakCanary, use i.e. `gradle :sample:installWithLeakCanaryDebug` to use it - Updated RequestParams documentation on handling arrays, sets and maps, along with new RequestParamsDebug sample - Added BlackholeHttpResponseHandler implementation, which discards all response contents and silents all various log messages (see #416) + - Added LogInterface, it's default implementation and interface option to disable/enable logging library-wide and set logging verbosity ## 1.4.7 (released 9. 5. 2015) diff --git a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java index 0907fac2b..69ce98abd 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java @@ -33,23 +33,27 @@ public class Redirect302Sample extends GetSample { private boolean enableRelativeRedirects = true; private boolean enableCircularRedirects = true; + private static final int MENU_ENABLE_REDIRECTS = 10; + private static final int MENU_ENABLE_CIRCULAR_REDIRECTS = 11; + private static final int MENU_ENABLE_RELATIVE_REDIRECTs = 12; + @Override public boolean onCreateOptionsMenu(Menu menu) { - menu.add(Menu.NONE, 0, Menu.NONE, "Enable redirects").setCheckable(true); - menu.add(Menu.NONE, 1, Menu.NONE, "Enable relative redirects").setCheckable(true); - menu.add(Menu.NONE, 2, Menu.NONE, "Enable circular redirects").setCheckable(true); + menu.add(Menu.NONE, MENU_ENABLE_REDIRECTS, Menu.NONE, "Enable redirects").setCheckable(true); + menu.add(Menu.NONE, MENU_ENABLE_RELATIVE_REDIRECTs, Menu.NONE, "Enable relative redirects").setCheckable(true); + menu.add(Menu.NONE, MENU_ENABLE_CIRCULAR_REDIRECTS, Menu.NONE, "Enable circular redirects").setCheckable(true); return super.onCreateOptionsMenu(menu); } @Override public boolean onPrepareOptionsMenu(Menu menu) { - MenuItem menuItemEnableRedirects = menu.findItem(0); + MenuItem menuItemEnableRedirects = menu.findItem(MENU_ENABLE_REDIRECTS); if (menuItemEnableRedirects != null) menuItemEnableRedirects.setChecked(enableRedirects); - MenuItem menuItemEnableRelativeRedirects = menu.findItem(1); + MenuItem menuItemEnableRelativeRedirects = menu.findItem(MENU_ENABLE_RELATIVE_REDIRECTs); if (menuItemEnableRelativeRedirects != null) menuItemEnableRelativeRedirects.setChecked(enableRelativeRedirects); - MenuItem menuItemEnableCircularRedirects = menu.findItem(2); + MenuItem menuItemEnableCircularRedirects = menu.findItem(MENU_ENABLE_CIRCULAR_REDIRECTS); if (menuItemEnableCircularRedirects != null) menuItemEnableCircularRedirects.setChecked(enableCircularRedirects); return super.onPrepareOptionsMenu(menu); @@ -59,11 +63,11 @@ public boolean onPrepareOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { if (item.isCheckable()) { item.setChecked(!item.isChecked()); - if (item.getItemId() == 0) { + if (item.getItemId() == MENU_ENABLE_REDIRECTS) { enableRedirects = item.isChecked(); - } else if (item.getItemId() == 1) { + } else if (item.getItemId() == MENU_ENABLE_RELATIVE_REDIRECTs) { enableRelativeRedirects = item.isChecked(); - } else if (item.getItemId() == 2) { + } else if (item.getItemId() == MENU_ENABLE_CIRCULAR_REDIRECTS) { enableCircularRedirects = item.isChecked(); } } diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java index 9336bf2ba..1ee17502a 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java @@ -20,7 +20,9 @@ import android.annotation.TargetApi; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.graphics.Color; import android.os.Build; import android.os.Bundle; @@ -75,8 +77,11 @@ protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpCon private static final int MENU_USE_HTTPS = 0; private static final int MENU_CLEAR_VIEW = 1; + private static final int MENU_LOGGING_VERBOSITY = 2; + private static final int MENU_ENABLE_LOGGING = 3; private boolean useHttps = true; + private boolean enableLogging = true; protected static final String PROTOCOL_HTTP = "http://"; protected static final String PROTOCOL_HTTPS = "https://"; @@ -128,6 +133,10 @@ public boolean onPrepareOptionsMenu(Menu menu) { if (useHttpsMenuItem != null) { useHttpsMenuItem.setChecked(useHttps); } + MenuItem enableLoggingMenuItem = menu.findItem(MENU_ENABLE_LOGGING); + if (enableLoggingMenuItem != null) { + enableLoggingMenuItem.setChecked(enableLogging); + } return super.onPrepareOptionsMenu(menu); } @@ -135,6 +144,8 @@ public boolean onPrepareOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) { menu.add(Menu.NONE, MENU_USE_HTTPS, Menu.NONE, R.string.menu_use_https).setCheckable(true); menu.add(Menu.NONE, MENU_CLEAR_VIEW, Menu.NONE, R.string.menu_clear_view); + menu.add(Menu.NONE, MENU_ENABLE_LOGGING, Menu.NONE, "Enable Logging").setCheckable(true); + menu.add(Menu.NONE, MENU_LOGGING_VERBOSITY, Menu.NONE, "Set Logging Verbosity"); return super.onCreateOptionsMenu(menu); } @@ -146,6 +157,13 @@ public boolean onOptionsItemSelected(MenuItem item) { PROTOCOL = useHttps ? PROTOCOL_HTTPS : PROTOCOL_HTTP; urlEditText.setText(getDefaultURL()); return true; + case MENU_ENABLE_LOGGING: + enableLogging = !enableLogging; + getAsyncHttpClient().setLoggingEnabled(enableLogging); + return true; + case MENU_LOGGING_VERBOSITY: + showLoggingVerbosityDialog(); + return true; case MENU_CLEAR_VIEW: clearOutputs(); return true; @@ -172,6 +190,29 @@ public void addRequestHandle(RequestHandle handle) { } } + private void showLoggingVerbosityDialog() { + AlertDialog ad = new AlertDialog.Builder(this) + .setTitle("Set Logging Verbosity") + .setSingleChoiceItems(new String[]{ + "VERBOSE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "WTF" + }, getAsyncHttpClient().getLoggingLevel() - 2, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + getAsyncHttpClient().setLoggingLevel(which + 2); + dialog.dismiss(); + } + }) + .setCancelable(true) + .setNeutralButton("Cancel", null) + .create(); + ad.show(); + } + public void onRunButtonPressed() { addRequestHandle(executeSample(getAsyncHttpClient(), getUrlText(getDefaultURL()), From 8b1243cfaab1822cb27bd475715c9af1a9d14454 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 23:23:36 +0200 Subject: [PATCH 089/167] Allow assign TAGs to RequestHandles and cancel requests that contain specific TAG --- .../loopj/android/http/AsyncHttpClient.java | 25 ++++++++++++++++++- .../com/loopj/android/http/RequestHandle.java | 20 +++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index df06d9209..c2ac317c0 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -20,7 +20,6 @@ import android.content.Context; import android.os.Looper; -import android.util.Log; import org.apache.http.Header; import org.apache.http.HeaderElement; @@ -829,6 +828,30 @@ public void cancelAllRequests(boolean mayInterruptIfRunning) { requestMap.clear(); } + /** + * Allows you to cancel all requests currently in queue or running, by set TAG, + * if passed TAG is null, will not attempt to cancel any requests, if TAG is null + * on RequestHandle, it cannot be canceled by this call + * + * @param TAG TAG to be matched in RequestHandle + * @param mayInterruptIfRunning specifies if active requests should be cancelled along with + * pending requests. + */ + public void cancelRequestsByTAG(Object TAG, boolean mayInterruptIfRunning) { + if (TAG == null) { + log.d(LOG_TAG, "cancelRequestsByTAG, passed TAG is null, cannot proceed"); + return; + } + for (List requestList : requestMap.values()) { + if (requestList != null) { + for (RequestHandle requestHandle : requestList) { + if (TAG.equals(requestHandle.getTag())) + requestHandle.cancel(mayInterruptIfRunning); + } + } + } + } + // [+] HTTP HEAD /** diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index 81018e0cc..46ff8b6fd 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -27,6 +27,7 @@ */ public class RequestHandle { private final WeakReference request; + private WeakReference TAG = null; public RequestHandle(AsyncHttpRequest request) { this.request = new WeakReference(request); @@ -95,4 +96,23 @@ public boolean shouldBeGarbageCollected() { request.clear(); return should; } + + /** + * Will set Object as TAG to this request, wrapped by WeakReference + * + * @param tag Object used as TAG to this RequestHandle + */ + public RequestHandle setTag(Object tag) { + TAG = new WeakReference(tag); + return this; + } + + /** + * Will return TAG of this RequestHandle + * + * @return Object TAG, can be null + */ + public Object getTag() { + return TAG.get(); + } } \ No newline at end of file From 90b69cf30f17b9af0d2a185e0f36b197354f0f40 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 23:31:00 +0200 Subject: [PATCH 090/167] Added Canceling by TAG sample, Closing #754 --- CHANGELOG.md | 1 + sample/src/main/AndroidManifest.xml | 1 + .../http/sample/CancelRequestByTagSample.java | 50 +++++++++++++++++++ .../sample/CancelRequestHandleSample.java | 2 +- .../android/http/sample/FilesSample.java | 2 +- .../http/sample/Http401AuthSample.java | 2 +- .../http/sample/WaypointsActivity.java | 1 + sample/src/main/res/values/strings.xml | 1 + 8 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a85df1098..538185841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Updated RequestParams documentation on handling arrays, sets and maps, along with new RequestParamsDebug sample - Added BlackholeHttpResponseHandler implementation, which discards all response contents and silents all various log messages (see #416) - Added LogInterface, it's default implementation and interface option to disable/enable logging library-wide and set logging verbosity + - Added option to TAG RequestHandle and cancel all requests matching specified TAG through `AsyncHttpClient.cancelRequestsByTAG(Object TAG)` ## 1.4.7 (released 9. 5. 2015) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 5ba56d9e6..0c642e88a 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -35,6 +35,7 @@ + diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java new file mode 100644 index 000000000..9039411f1 --- /dev/null +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java @@ -0,0 +1,50 @@ +/* + Android Asynchronous Http Client Sample + Copyright (c) 2014 Marek Sebera + http://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.loopj.android.http.sample; + +import android.util.Log; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.RequestHandle; +import com.loopj.android.http.ResponseHandlerInterface; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; + +public class CancelRequestByTagSample extends ThreadingTimeoutSample { + + private static final String LOG_TAG = "CancelRequestByTagSample"; + private static final Integer REQUEST_TAG = 132435; + + @Override + public int getSampleTitle() { + return R.string.title_cancel_tag; + } + + @Override + public void onCancelButtonPressed() { + Log.d(LOG_TAG, "Canceling requests by TAG: " + REQUEST_TAG); + getAsyncHttpClient().cancelRequestsByTAG(REQUEST_TAG, false); + } + + @Override + public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { + return client.get(this, URL, headers, null, responseHandler).setTag(REQUEST_TAG); + } +} diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java index 7db7ba727..101a88e72 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java @@ -24,7 +24,7 @@ public class CancelRequestHandleSample extends ThreadingTimeoutSample { - private static final String LOG_TAG = "ThreadingTimeoutSample"; + private static final String LOG_TAG = "CancelRequestHandleSample"; @Override public int getSampleTitle() { diff --git a/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java b/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java index fb97a41b0..1167aa4fa 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java @@ -17,7 +17,7 @@ public class FilesSample extends PostSample { - public static final String LOG_TAG = "PostFilesSample"; + public static final String LOG_TAG = "FilesSample"; @Override public int getSampleTitle() { diff --git a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java index 16122e0de..e70cff4b6 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java @@ -50,7 +50,7 @@ */ public class Http401AuthSample extends GetSample { - private static final String LOG_TAG = "Http401Auth"; + private static final String LOG_TAG = "Http401AuthSample"; private static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate"; private static final String HEADER_AUTHORIZATION = "Authorization"; private static final String HEADER_REALM_PREFIX = "realm="; diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java index 0cccdfe3b..dc02d306e 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java @@ -47,6 +47,7 @@ public class WaypointsActivity extends ListActivity { new SampleConfig(R.string.title_threading_timeout, ThreadingTimeoutSample.class), new SampleConfig(R.string.title_cancel_all, CancelAllRequestsSample.class), new SampleConfig(R.string.title_cancel_handle, CancelRequestHandleSample.class), + new SampleConfig(R.string.title_cancel_tag, CancelRequestByTagSample.class), new SampleConfig(R.string.title_synchronous, SynchronousClientSample.class), new SampleConfig(R.string.title_intent_service_sample, IntentServiceSample.class), new SampleConfig(R.string.title_post_files, FilesSample.class), diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 11f28ca54..8486e50bc 100755 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -30,6 +30,7 @@ Cancel all requests SAX Example Cancel request handle + Cancel by TAG Synchronous GET request Threading timeouts GET Gzipped JSON and parse it From e1b704765ff088acf88766a050b0e6cfca00baef Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 23:36:05 +0200 Subject: [PATCH 091/167] Missing javadoc return statement --- library/src/main/java/com/loopj/android/http/RequestHandle.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index 46ff8b6fd..e557e14a6 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -101,6 +101,7 @@ public boolean shouldBeGarbageCollected() { * Will set Object as TAG to this request, wrapped by WeakReference * * @param tag Object used as TAG to this RequestHandle + * @return this RequestHandle to allow fluid syntax */ public RequestHandle setTag(Object tag) { TAG = new WeakReference(tag); From c45f898dbc9dad7edb0a850c6cf2e78a59d9e856 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 23:40:12 +0200 Subject: [PATCH 092/167] Removed deprecated methods, in new version devs are forced to use correct new calls --- CHANGELOG.md | 2 ++ .../loopj/android/http/AsyncHttpClient.java | 21 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 538185841..2c62ad1e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ - Added BlackholeHttpResponseHandler implementation, which discards all response contents and silents all various log messages (see #416) - Added LogInterface, it's default implementation and interface option to disable/enable logging library-wide and set logging verbosity - Added option to TAG RequestHandle and cancel all requests matching specified TAG through `AsyncHttpClient.cancelRequestsByTAG(Object TAG)` + - Removed deprecated `getTimeout()` replaced by `getConnectTimeout()` and `getResponseTimeout()` respectively + - Removed deprecated `clearBasicAuth()` replaced by `clearCredentialsProvider()` ## 1.4.7 (released 9. 5. 2015) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index c2ac317c0..2b3ffce0f 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -533,17 +533,6 @@ public void setMaxConnections(int maxConnections) { ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(this.maxConnections)); } - /** - * Returns current socket timeout limit (milliseconds). By default, this is - * set to 10 seconds. - * - * @return Socket Timeout limit in milliseconds - * @deprecated Use either {@link #getConnectTimeout()} or {@link #getResponseTimeout()} - */ - public int getTimeout() { - return connectTimeout; - } - /** * Set both the connection and socket timeouts. By default, both are set to * 10 seconds. @@ -751,16 +740,6 @@ public void setAuthenticationPreemptive(boolean isPreemptive) { } } - /** - * Removes previously set basic auth credentials - * - * @deprecated - */ - @Deprecated - public void clearBasicAuth() { - clearCredentialsProvider(); - } - /** * Removes previously set auth credentials */ From 8406802ef0febc98aa95aa6b56d8ddeb5e6d3647 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 23:47:40 +0200 Subject: [PATCH 093/167] Lint issues fixed (unused imports, unnecessary casts, simplified checking in JsonStreamerEntity) --- .../main/java/com/loopj/android/http/AsyncHttpRequest.java | 2 -- .../com/loopj/android/http/AsyncHttpResponseHandler.java | 1 - .../com/loopj/android/http/BaseJsonHttpResponseHandler.java | 2 -- .../com/loopj/android/http/BinaryHttpResponseHandler.java | 1 - .../loopj/android/http/DataAsyncHttpResponseHandler.java | 1 - .../loopj/android/http/FileAsyncHttpResponseHandler.java | 1 - .../com/loopj/android/http/JsonHttpResponseHandler.java | 6 ++---- .../java/com/loopj/android/http/JsonStreamerEntity.java | 3 +-- .../java/com/loopj/android/http/PersistentCookieStore.java | 1 - .../android/http/RangeFileAsyncHttpResponseHandler.java | 2 -- .../src/main/java/com/loopj/android/http/RequestParams.java | 2 -- .../com/loopj/android/http/SaxAsyncHttpResponseHandler.java | 2 -- .../java/com/loopj/android/http/SimpleMultipartEntity.java | 1 - .../com/loopj/android/http/TextHttpResponseHandler.java | 2 -- 14 files changed, 3 insertions(+), 24 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index 451a4719e..748d1570f 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.HttpResponse; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.methods.HttpUriRequest; diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 625512bd8..2ee33a60b 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -21,7 +21,6 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.util.Log; import org.apache.http.Header; import org.apache.http.HttpEntity; diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java index 21f9f59a7..c9a42a7ae 100755 --- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.Header; import org.apache.http.HttpStatus; diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index 68e7076d2..f6a6881d8 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -19,7 +19,6 @@ package com.loopj.android.http; import android.os.Looper; -import android.util.Log; import org.apache.http.Header; import org.apache.http.HttpResponse; diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index 7f1360ec7..f843e1347 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -19,7 +19,6 @@ package com.loopj.android.http; import android.os.Message; -import android.util.Log; import org.apache.http.HttpEntity; import org.apache.http.util.ByteArrayBuffer; diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 23e043e33..ec979868c 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -19,7 +19,6 @@ package com.loopj.android.http; import android.content.Context; -import android.util.Log; import org.apache.http.Header; import org.apache.http.HttpEntity; diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index 84ded1791..c83637ecf 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.Header; import org.apache.http.HttpStatus; import org.json.JSONArray; @@ -148,7 +146,7 @@ public void run() { public void run() { // In RFC5179 a null value is not a valid JSON if (!useRFC5179CompatibilityMode && jsonResponse == null) { - onSuccess(statusCode, headers, (String) jsonResponse); + onSuccess(statusCode, headers, (String) null); } else if (jsonResponse instanceof JSONObject) { onSuccess(statusCode, headers, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { @@ -199,7 +197,7 @@ public void run() { public void run() { // In RFC5179 a null value is not a valid JSON if (!useRFC5179CompatibilityMode && jsonResponse == null) { - onFailure(statusCode, headers, (String) jsonResponse, throwable); + onFailure(statusCode, headers, (String) null, throwable); } else if (jsonResponse instanceof JSONObject) { onFailure(statusCode, headers, throwable, (JSONObject) jsonResponse); } else if (jsonResponse instanceof JSONArray) { diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index 51cb4f9b0..63940262c 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -19,7 +19,6 @@ package com.loopj.android.http; import android.text.TextUtils; -import android.util.Log; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -374,7 +373,7 @@ static byte[] escape(String string) { break; default: // Reference: http://www.unicode.org/versions/Unicode5.1.0/ - if ((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) { + if ((ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) { String intString = Integer.toHexString(ch); sb.append("\\u"); int intLength = 4 - intString.length(); diff --git a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java index c35027137..87db21b5d 100755 --- a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java +++ b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils; -import android.util.Log; import org.apache.http.client.CookieStore; import org.apache.http.cookie.Cookie; diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index 038fe6489..ae1032138 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 9377ede3e..0123d24fe 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.HttpEntity; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.utils.URLEncodedUtils; diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index 1da440eeb..157b87a3e 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.Header; import org.apache.http.HttpEntity; import org.xml.sax.InputSource; diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index 4ee81b6d8..1f3db6b75 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -24,7 +24,6 @@ package com.loopj.android.http; import android.text.TextUtils; -import android.util.Log; import org.apache.http.Header; import org.apache.http.HttpEntity; diff --git a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java index a9ea55bf5..1ed7233f6 100755 --- a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import android.util.Log; - import org.apache.http.Header; import java.io.UnsupportedEncodingException; From 0107712c401dc103ddff33a69621ef7dabee77c0 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 16 Jul 2015 23:54:54 +0200 Subject: [PATCH 094/167] Avoid possible NPE on getTag if no was set before --- library/src/main/java/com/loopj/android/http/RequestHandle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index e557e14a6..a21a7a22b 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -27,7 +27,7 @@ */ public class RequestHandle { private final WeakReference request; - private WeakReference TAG = null; + private WeakReference TAG = new WeakReference(null); public RequestHandle(AsyncHttpRequest request) { this.request = new WeakReference(request); From af7e9e4bcd90504d6a665dbb21635eb1733fe025 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Fri, 17 Jul 2015 00:18:15 +0200 Subject: [PATCH 095/167] Modified #754 solution to place TAG within ResponseHandlerInterface implementation, so it can be used as identification of request/response pair, Closing #552 --- .../loopj/android/http/AsyncHttpRequest.java | 20 +++++++++++++++++++ .../http/AsyncHttpResponseHandler.java | 14 ++++++++++++- .../com/loopj/android/http/RequestHandle.java | 14 +++++++------ .../http/ResponseHandlerInterface.java | 15 ++++++++++++++ 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index 748d1570f..5d7790548 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -234,4 +234,24 @@ public boolean cancel(boolean mayInterruptIfRunning) { request.abort(); return isCancelled(); } + + /** + * Will set Object as TAG to this request, wrapped by WeakReference + * + * @param TAG Object used as TAG to this RequestHandle + * @return this AsyncHttpRequest to allow fluid syntax + */ + public AsyncHttpRequest setRequestTag(Object TAG) { + this.responseHandler.setTag(TAG); + return this; + } + + /** + * Will return TAG of this AsyncHttpRequest + * + * @return Object TAG, can be null, if it's been already garbage collected + */ + public Object getTag() { + return this.responseHandler.getTag(); + } } diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 2ee33a60b..2cc417b9e 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.ref.WeakReference; import java.net.URI; /** @@ -102,6 +103,7 @@ public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterfa private URI requestURI = null; private Header[] requestHeaders = null; private Looper looper = null; + private WeakReference TAG = new WeakReference(null); /** * Creates a new AsyncHttpResponseHandler @@ -147,6 +149,16 @@ public AsyncHttpResponseHandler(boolean usePoolThread) { } } + @Override + public void setTag(Object TAG) { + this.TAG = new WeakReference(TAG); + } + + @Override + public Object getTag() { + return this.TAG.get(); + } + @Override public URI getRequestURI() { return this.requestURI; @@ -399,7 +411,7 @@ protected void handleMessage(Message message) { onCancel(); break; } - } catch(Throwable error) { + } catch (Throwable error) { onUserException(error); } } diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index a21a7a22b..1eb3c0d34 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -27,7 +27,6 @@ */ public class RequestHandle { private final WeakReference request; - private WeakReference TAG = new WeakReference(null); public RequestHandle(AsyncHttpRequest request) { this.request = new WeakReference(request); @@ -98,22 +97,25 @@ public boolean shouldBeGarbageCollected() { } /** - * Will set Object as TAG to this request, wrapped by WeakReference + * Will set Object as TAG to underlying AsyncHttpRequest * - * @param tag Object used as TAG to this RequestHandle + * @param tag Object used as TAG to underlying AsyncHttpRequest * @return this RequestHandle to allow fluid syntax */ public RequestHandle setTag(Object tag) { - TAG = new WeakReference(tag); + AsyncHttpRequest _request = request.get(); + if (_request != null) + _request.setRequestTag(tag); return this; } /** - * Will return TAG of this RequestHandle + * Will return TAG of underlying AsyncHttpRequest if it's not already GCed * * @return Object TAG, can be null */ public Object getTag() { - return TAG.get(); + AsyncHttpRequest _request = request.get(); + return _request == null ? null : _request.getTag(); } } \ No newline at end of file diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index e438e68a2..fcba44961 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -171,4 +171,19 @@ public interface ResponseHandlerInterface { * @param response The response to post-process */ void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response); + + /** + * Will set TAG to ResponseHandlerInterface implementation, which can be then obtained + * in implemented methods, such as onSuccess, onFailure, ... + * + * @param TAG Object to be set as TAG, will be placed in WeakReference + */ + void setTag(Object TAG); + + /** + * Will retrieve TAG Object if it's not already freed from memory + * + * @return Object TAG or null if it's been garbage collected + */ + Object getTag(); } From cf95c42823d07364b7f9fecd31204862d81828b5 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Fri, 17 Jul 2015 00:19:20 +0200 Subject: [PATCH 096/167] Updated Sample application to show capability of obtaining TAG within ResponseHandler, #552 --- .../http/sample/CancelRequestByTagSample.java | 34 +++++++++++++++++++ .../http/sample/ThreadingTimeoutSample.java | 6 ++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java index 9039411f1..f3c063fa8 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java @@ -21,6 +21,7 @@ import android.util.Log; import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; @@ -43,6 +44,39 @@ public void onCancelButtonPressed() { getAsyncHttpClient().cancelRequestsByTAG(REQUEST_TAG, false); } + @Override + public ResponseHandlerInterface getResponseHandler() { + return new AsyncHttpResponseHandler() { + + private final int id = counter++; + + @Override + public void onStart() { + setStatus(id, "TAG:" + getTag() + ", START"); + } + + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + setStatus(id, "SUCCESS"); + } + + @Override + public void onFinish() { + setStatus(id, "FINISH"); + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + setStatus(id, "FAILURE"); + } + + @Override + public void onCancel() { + setStatus(id, "CANCEL"); + } + }; + } + @Override public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { return client.get(this, URL, headers, null, responseHandler).setTag(REQUEST_TAG); diff --git a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java index 2bf842294..052f03057 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java @@ -31,8 +31,8 @@ public class ThreadingTimeoutSample extends SampleParentActivity { private static final String LOG_TAG = "ThreadingTimeoutSample"; - private final SparseArray states = new SparseArray(); - private int counter = 0; + protected final SparseArray states = new SparseArray(); + protected int counter = 0; @Override public int getSampleTitle() { @@ -59,7 +59,7 @@ public String getDefaultURL() { return PROTOCOL + "httpbin.org/delay/6"; } - private synchronized void setStatus(int id, String status) { + protected synchronized void setStatus(int id, String status) { String current = states.get(id, null); states.put(id, current == null ? status : current + "," + status); clearOutputs(); From cf70d2e43a46e8cfd0154ddef41b2526f3eadaaa Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Fri, 17 Jul 2015 20:42:03 +0200 Subject: [PATCH 097/167] Release version 1.4.8 --- CHANGELOG.md | 7 +++++-- README.md | 19 ++++++++----------- build.gradle | 2 +- gradle.properties | 4 ++-- releases/android-async-http-1.4.8.jar | Bin 0 -> 106515 bytes sample/src/main/AndroidManifest.xml | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 releases/android-async-http-1.4.8.jar diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c62ad1e6..72536aa30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # CHANGELOG -## 1.4.8 (future release) +## 1.4.8 (released 17. 7. 2015) + +Complete list of commits included is here [https://github.com/loopj/android-async-http/commits/1.4.8](https://github.com/loopj/android-async-http/commits/1.4.8) +List of closed issues is here [https://github.com/loopj/android-async-http/issues?milestone=7&state=closed](https://github.com/loopj/android-async-http/issues?milestone=7&state=closed) - New constructor for BinaryHttpResponseHandler which takes Looper as argument (thanks to @ScottFrank) - SaxAsyncHttpResponseHandler can be now provided with custom charset, instead of just using default one @@ -18,7 +21,7 @@ ## 1.4.7 (released 9. 5. 2015) -Complete list of commits included is here [https://github.com/loopj/android-async-http/commits/1.4.7](https://github.com/loopj/android-async-http/commits/1.4.7) +Complete list of commits included is here [https://github.com/loopj/android-async-http/commits/1.4.7](https://github.com/loopj/android-async-http/commits1.4.7) List of closed issues is here [https://github.com/loopj/android-async-http/issues?milestone=6&state=closed](https://github.com/loopj/android-async-http/issues?milestone=6&state=closed) - Fixed crash when canceling through RequestHandle from UI Thread (NetworkOnMainThreadException) diff --git a/README.md b/README.md index 8a48b11e6..234c81ffd 100755 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ An asynchronous, callback-based Http client for Android built on top of Apache's Changelog --------- -See what is new in version 1.4.7 released on 9th May 2015 +See what is new in version 1.4.8 released on 17th July 2015 -https://github.com/loopj/android-async-http/blob/1.4.7/CHANGELOG.md +https://github.com/loopj/android-async-http/blob/1.4.8/CHANGELOG.md Javadoc ------- -Latest Javadoc for 1.4.7 release are available here (also included in Maven repository): +Latest Javadoc for 1.4.8 release are available here (also included in Maven repository): http://loopj.com/android-async-http/doc/ @@ -35,7 +35,7 @@ Examples -------- For inspiration and testing on device we've provided Sample Application. -See individual samples [here on Github](https://github.com/loopj/android-async-http/tree/1.4.7/sample/src/main/java/com/loopj/android/http/sample) +See individual samples [here on Github](https://github.com/loopj/android-async-http/tree/1.4.8/sample/src/main/java/com/loopj/android/http/sample) To run Sample application, simply clone the repository and run this command, to install it on connected device ```java @@ -53,10 +53,10 @@ http://central.maven.org/maven2/com/loopj/android/android-async-http/ Maven URL: http://repo1.maven.org/maven2/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.7 +Version: 1.4.8 Packaging: JAR or AAR ``` -Gradle: `com.loopj.android:android-async-http:1.4.7` +Gradle: `com.loopj.android:android-async-http:1.4.8` **development snapshots** @@ -65,10 +65,10 @@ https://oss.sonatype.org/content/repositories/snapshots/com/loopj/android/androi Maven URL: https://oss.sonatype.org/content/repositories/snapshots/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.8-SNAPSHOT +Version: 1.4.9-SNAPSHOT Packaging: JAR or AAR ``` -Gradle: `com.loopj.android:android-async-http:1.4.8-SNAPSHOT` +Gradle: `com.loopj.android:android-async-http:1.4.9-SNAPSHOT` Documentation, Features and Examples ------------------------------------ @@ -76,6 +76,3 @@ Full details and documentation can be found on the project page here: http://loopj.com/android-async-http/ - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/loopj/android-async-http/trend.png)](https://bitdeli.com/free "Bitdeli Badge") - diff --git a/build.gradle b/build.gradle index 94018ee29..58f100fc2 100755 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.4.8-SNAPSHOT' + version = '1.4.8' repositories { mavenCentral() diff --git a/gradle.properties b/gradle.properties index c7c5dc86f..0c8f2af1d 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,9 @@ -VERSION_NAME=1.4.8-SNAPSHOT +VERSION_NAME=1.4.8 VERSION_CODE=148 GROUP=com.loopj.android POM_DESCRIPTION=An Asynchronous HTTP Library for Android -POM_URL=loopj.com/android-async-http/ +POM_URL=https://loopj.com/android-async-http/ POM_SCM_URL=https://github.com/loopj/android-async-http POM_SCM_CONNECTION=scm:git@github.com:loopj/android-async-http.git POM_SCM_DEV_CONNECTION=scm:git@github.com:loopj/android-async-http.git diff --git a/releases/android-async-http-1.4.8.jar b/releases/android-async-http-1.4.8.jar new file mode 100644 index 0000000000000000000000000000000000000000..74664cca1324e44c235e175ae53a1e156ffdab17 GIT binary patch literal 106515 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%0A;!{yF{kKDYRI6_bgI99XO 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 + android:versionCode="4" + android:versionName="1.4.8"> From 769e809ad1ea414aec30d2a77f19645a646d2f6a Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Fri, 17 Jul 2015 20:48:29 +0200 Subject: [PATCH 098/167] Prepare 1.4.9-SNAPSHOT dev environment --- build.gradle | 2 +- gradle.properties | 4 ++-- sample/src/main/AndroidManifest.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 58f100fc2..97d2df08a 100755 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.4.8' + version = '1.4.9-SNAPSHOT' repositories { mavenCentral() diff --git a/gradle.properties b/gradle.properties index 0c8f2af1d..715f09519 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=1.4.8 -VERSION_CODE=148 +VERSION_NAME=1.4.9-SNAPSHOT +VERSION_CODE=149 GROUP=com.loopj.android POM_DESCRIPTION=An Asynchronous HTTP Library for Android diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 2d6ce7d7a..e6fee30c9 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="5" + android:versionName="1.4.9-SNAPSHOT"> From 400537ce180e9cdd181b8e075ece1d6468edb545 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Fri, 17 Jul 2015 21:20:37 +0200 Subject: [PATCH 099/167] HTTP->HTTPS where applicable --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 2 +- NOTICE.txt | 4 ++-- README.md | 10 +++++----- gradle.properties | 2 +- .../java/com/loopj/android/http/AsyncHttpClient.java | 8 ++++---- .../java/com/loopj/android/http/AsyncHttpRequest.java | 6 +++--- .../loopj/android/http/AsyncHttpResponseHandler.java | 8 ++++---- .../src/main/java/com/loopj/android/http/Base64.java | 6 +++--- .../com/loopj/android/http/Base64DataException.java | 2 +- .../com/loopj/android/http/Base64OutputStream.java | 2 +- .../android/http/BaseJsonHttpResponseHandler.java | 6 +++--- .../loopj/android/http/BinaryHttpResponseHandler.java | 6 +++--- .../android/http/DataAsyncHttpResponseHandler.java | 4 ++-- .../android/http/FileAsyncHttpResponseHandler.java | 4 ++-- .../main/java/com/loopj/android/http/HttpDelete.java | 4 ++-- .../src/main/java/com/loopj/android/http/HttpGet.java | 4 ++-- .../main/java/com/loopj/android/http/HttpPatch.java | 4 ++-- .../loopj/android/http/JsonHttpResponseHandler.java | 4 ++-- .../com/loopj/android/http/JsonStreamerEntity.java | 8 ++++---- .../com/loopj/android/http/JsonValueInterface.java | 4 ++-- .../java/com/loopj/android/http/MyRedirectHandler.java | 4 ++-- .../com/loopj/android/http/MySSLSocketFactory.java | 6 +++--- .../com/loopj/android/http/PersistentCookieStore.java | 4 ++-- .../PreemptiveAuthorizationHttpRequestInterceptor.java | 4 ++-- .../http/RangeFileAsyncHttpResponseHandler.java | 4 ++-- .../java/com/loopj/android/http/RequestHandle.java | 4 ++-- .../java/com/loopj/android/http/RequestParams.java | 6 +++--- .../loopj/android/http/ResponseHandlerInterface.java | 4 ++-- .../main/java/com/loopj/android/http/RetryHandler.java | 4 ++-- .../android/http/SaxAsyncHttpResponseHandler.java | 4 ++-- .../com/loopj/android/http/SerializableCookie.java | 4 ++-- .../com/loopj/android/http/SimpleMultipartEntity.java | 10 +++++----- .../java/com/loopj/android/http/SyncHttpClient.java | 4 ++-- .../loopj/android/http/TextHttpResponseHandler.java | 6 +++--- .../src/main/java/com/loopj/android/http/Utils.java | 4 ++-- .../main/java/com/loopj/android/http/package-info.java | 4 ++-- maven_push.gradle | 2 +- .../http/sample/AsyncBackgroundThreadSample.java | 4 ++-- .../com/loopj/android/http/sample/BinarySample.java | 4 ++-- .../android/http/sample/CancelAllRequestsSample.java | 4 ++-- .../android/http/sample/CancelRequestByTagSample.java | 4 ++-- .../android/http/sample/CancelRequestHandleSample.java | 4 ++-- .../com/loopj/android/http/sample/CustomCASample.java | 6 +++--- .../com/loopj/android/http/sample/DeleteSample.java | 4 ++-- .../com/loopj/android/http/sample/DirectorySample.java | 4 ++-- .../java/com/loopj/android/http/sample/FileSample.java | 4 ++-- .../java/com/loopj/android/http/sample/GetSample.java | 4 ++-- .../java/com/loopj/android/http/sample/GzipSample.java | 4 ++-- .../loopj/android/http/sample/Http401AuthSample.java | 4 ++-- .../java/com/loopj/android/http/sample/JsonSample.java | 4 ++-- .../loopj/android/http/sample/JsonStreamerSample.java | 4 ++-- .../android/http/sample/PersistentCookiesSample.java | 4 ++-- .../java/com/loopj/android/http/sample/PostSample.java | 4 ++-- .../android/http/sample/PrePostProcessingSample.java | 4 ++-- .../java/com/loopj/android/http/sample/PutSample.java | 4 ++-- .../loopj/android/http/sample/RangeResponseSample.java | 6 +++--- .../loopj/android/http/sample/Redirect302Sample.java | 4 ++-- .../loopj/android/http/sample/RetryRequestSample.java | 4 ++-- .../com/loopj/android/http/sample/SampleInterface.java | 4 ++-- .../android/http/sample/SampleParentActivity.java | 4 ++-- .../java/com/loopj/android/http/sample/SaxSample.java | 4 ++-- .../android/http/sample/SynchronousClientSample.java | 4 ++-- .../android/http/sample/ThreadingTimeoutSample.java | 4 ++-- .../loopj/android/http/sample/WaypointsActivity.java | 4 ++-- .../com/loopj/android/http/sample/package-info.java | 4 ++-- .../android/http/sample/services/package-info.java | 4 ++-- .../com/loopj/android/http/sample/util/FileUtil.java | 6 +++--- .../com/loopj/android/http/sample/util/SampleJSON.java | 4 ++-- .../android/http/sample/util/SecureSocketFactory.java | 4 ++-- .../loopj/android/http/sample/util/package-info.java | 4 ++-- 71 files changed, 158 insertions(+), 158 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72536aa30..fd8a4f6de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,7 +130,7 @@ List of closed issues is here [https://github.com/loopj/android-async-http/issue - Is returned for each call (`.post(...)`, `.get(...)`, `.head(...)`, `.put(...)`, etc..) - Added BaseJsonHttpResponseHandler to simplify integration with Jackson JSON, Gson and other JSON parsing libraries - Added Sample application to demonstrate functions and usage - - Using [http://httpbin.org/](http://httpbin.org/) to test methods + - Using [https://httpbin.org/](https://httpbin.org/) to test methods - Enforcing INTERNET permission - Support for Gradle buildscript - Support for Travis CI (Continuous Integration) testing diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc55a3b23..fa99f5847 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ Don't be discouraged if your pull request is rejected. This is not a deadline an ISSUES --------- -![Read the ISSUES?](http://i.imgur.com/LPWyLe7.jpg "Read the ISSUES?") +![Read the ISSUES?](https://i.imgur.com/LPWyLe7.jpg "Read the ISSUES?") The issues system is the place to report bugs and not for submitting patches or new functionality. As helpful as we would like to be, we cannot replace the developer and we certainly do not see what you're seeing. So when you come to report an issue, follow these simple rules: diff --git a/NOTICE.txt b/NOTICE.txt index aea75d844..45deb1012 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,6 +1,6 @@ Android Async Http Client library Copyright (c) 2011-2015 James Smith -http://loopj.com +https://loopj.com This product includes software developed by -The Apache Software Foundation (http://www.apache.org/). +The Apache Software Foundation (https://www.apache.org/). diff --git a/README.md b/README.md index 234c81ffd..2150dedd4 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Asynchronous Http Client for Android ==================================== [![Build Status](https://travis-ci.org/loopj/android-async-http.png?branch=master)](https://travis-ci.org/loopj/android-async-http) -An asynchronous, callback-based Http client for Android built on top of Apache's [HttpClient](http://hc.apache.org/httpcomponents-client-ga/) libraries. +An asynchronous, callback-based Http client for Android built on top of Apache's [HttpClient](https://hc.apache.org/httpcomponents-client-ga/) libraries. Changelog --------- @@ -16,7 +16,7 @@ Javadoc Latest Javadoc for 1.4.8 release are available here (also included in Maven repository): -http://loopj.com/android-async-http/doc/ +https://loopj.com/android-async-http/doc/ Features -------- @@ -48,9 +48,9 @@ You can now integrate this library in your project via Maven. There are availabl **releases, maven central** -http://central.maven.org/maven2/com/loopj/android/android-async-http/ +https://repo1.maven.org/maven2/com/loopj/android/android-async-http/ ``` -Maven URL: http://repo1.maven.org/maven2/ +Maven URL: https://repo1.maven.org/maven2/ GroupId: com.loopj.android ArtifactId: android-async-http Version: 1.4.8 @@ -74,5 +74,5 @@ Documentation, Features and Examples ------------------------------------ Full details and documentation can be found on the project page here: -http://loopj.com/android-async-http/ +https://loopj.com/android-async-http/ diff --git a/gradle.properties b/gradle.properties index 715f09519..ff934178d 100755 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ POM_SCM_URL=https://github.com/loopj/android-async-http POM_SCM_CONNECTION=scm:git@github.com:loopj/android-async-http.git POM_SCM_DEV_CONNECTION=scm:git@github.com:loopj/android-async-http.git POM_LICENCE_NAME=The Apache Software License, Version 2.0 -POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo POM_DEVELOPER_ID=jamessmith diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 2b3ffce0f..b9ee31352 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -94,7 +94,7 @@ * ResponseHandlerInterface} instance.

 

For example:

 

*
  * AsyncHttpClient client = new AsyncHttpClient();
- * client.get("http://www.google.com/", new AsyncHttpResponseHandler() {
+ * client.get("https://www.google.com/", new AsyncHttpResponseHandler() {
  *     @Override
  *     public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
  *          System.out.println(response);
@@ -502,7 +502,7 @@ public void setRedirectHandler(final RedirectHandler customRedirectHandler) {
 
     /**
      * Sets the User-Agent header to be sent with each request. By default, "Android Asynchronous
-     * Http Client/VERSION (http://loopj.com/android-async-http/)" is used.
+     * Http Client/VERSION (https://loopj.com/android-async-http/)" is used.
      *
      * @param userAgent the string to use in the User-Agent header.
      */
diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java
index 5d7790548..f8a49d5c1 100755
--- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java
+++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -185,7 +185,7 @@ private void makeRequestWithRetries() throws IOException {
                 } catch (NullPointerException e) {
                     // there's a bug in HttpClient 4.0.x that on some occasions causes
                     // DefaultRequestExecutor to throw an NPE, see
-                    // http://code.google.com/p/android/issues/detail?id=5255
+                    // https://code.google.com/p/android/issues/detail?id=5255
                     cause = new IOException("NPE in HttpClient: " + e.getMessage());
                     retry = retryHandler.retryRequest(cause, ++executionCount, context);
                 } catch (IOException e) {
diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java
index 2cc417b9e..5aa3524f0 100755
--- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -43,7 +43,7 @@
  * 

 

For example:

 

*
  * AsyncHttpClient client = new AsyncHttpClient();
- * client.get("http://www.google.com/", new AsyncHttpResponseHandler() {
+ * client.get("https://www.google.com/", new AsyncHttpResponseHandler() {
  *     @Override
  *     public void onStart() {
  *         // Initiated the request
@@ -242,7 +242,7 @@ public void setUsePoolThread(boolean pool) {
      * Sets the charset for the response string. If not set, the default is UTF-8.
      *
      * @param charset to be used for the response string.
-     * @see Charset
+     * @see Charset
      */
     public void setCharset(final String charset) {
         this.responseCharset = charset;
diff --git a/library/src/main/java/com/loopj/android/http/Base64.java b/library/src/main/java/com/loopj/android/http/Base64.java
index cc26d4398..d994700fe 100755
--- a/library/src/main/java/com/loopj/android/http/Base64.java
+++ b/library/src/main/java/com/loopj/android/http/Base64.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,7 +20,7 @@
 
 /**
  * Utilities for encoding and decoding the Base64 representation of binary data.  See RFCs 2045 and 3548.
+ * href="https://www.ietf.org/rfc/rfc2045.txt">2045 and 3548.
  */
 public class Base64 {
     /**
@@ -520,7 +520,7 @@ public static byte[] encode(byte[] input, int offset, int len, int flags) {
     /* package */ static class Encoder extends Coder {
         /**
          * Emit a new line every this many output tuples.  Corresponds to a 76-character line length
-         * (the maximum allowable according to RFC
+         * (the maximum allowable according to RFC
          * 2045).
          */
         public static final int LINE_GROUPS = 19;
diff --git a/library/src/main/java/com/loopj/android/http/Base64DataException.java b/library/src/main/java/com/loopj/android/http/Base64DataException.java
index ea2af5428..50127c1f4 100755
--- a/library/src/main/java/com/loopj/android/http/Base64DataException.java
+++ b/library/src/main/java/com/loopj/android/http/Base64DataException.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/Base64OutputStream.java b/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
index 036d4a28c..aa14ea459 100755
--- a/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
+++ b/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java
index c9a42a7ae..02d7ec9b2 100755
--- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -43,7 +43,7 @@ public BaseJsonHttpResponseHandler() {
     /**
      * Creates a new JsonHttpResponseHandler with given string encoding
      *
-     * @param encoding result string encoding, see Charset
+     * @param encoding result string encoding, see Charset
      */
     public BaseJsonHttpResponseHandler(String encoding) {
         super(encoding);
diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java
index f6a6881d8..a891af560 100755
--- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -36,7 +36,7 @@
  * 
  * AsyncHttpClient client = new AsyncHttpClient();
  * String[] allowedTypes = new String[] { "image/png" };
- * client.get("http://www.example.com/image.png", new BinaryHttpResponseHandler(allowedTypes) {
+ * client.get("https://www.example.com/image.png", new BinaryHttpResponseHandler(allowedTypes) {
  *     @Override
  *     public void onSuccess(byte[] imageData) {
  *         // Successfully got a response
diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java
index f843e1347..1d3ade69e 100755
--- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java
index ec979868c..0fc1bec46 100755
--- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/HttpDelete.java b/library/src/main/java/com/loopj/android/http/HttpDelete.java
index fa5287290..103a997be 100644
--- a/library/src/main/java/com/loopj/android/http/HttpDelete.java
+++ b/library/src/main/java/com/loopj/android/http/HttpDelete.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/HttpGet.java b/library/src/main/java/com/loopj/android/http/HttpGet.java
index 4c639e8c2..b5582737e 100644
--- a/library/src/main/java/com/loopj/android/http/HttpGet.java
+++ b/library/src/main/java/com/loopj/android/http/HttpGet.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/HttpPatch.java b/library/src/main/java/com/loopj/android/http/HttpPatch.java
index f0963d409..82e0c8714 100644
--- a/library/src/main/java/com/loopj/android/http/HttpPatch.java
+++ b/library/src/main/java/com/loopj/android/http/HttpPatch.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java
index c83637ecf..5fa926912 100755
--- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java
index 63940262c..d191ab1e8 100755
--- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java
+++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -332,7 +332,7 @@ private void endMetaData(OutputStream os) throws IOException {
         os.write('"');
     }
 
-    // Curtosy of Simple-JSON: http://goo.gl/XoW8RF
+    // Curtosy of Simple-JSON: https://goo.gl/XoW8RF
     // Changed a bit to suit our needs in this class.
     static byte[] escape(String string) {
         // If it's null, just return prematurely.
@@ -372,7 +372,7 @@ static byte[] escape(String string) {
                     sb.append("\\t");
                     break;
                 default:
-                    // Reference: http://www.unicode.org/versions/Unicode5.1.0/
+                    // Reference: https://www.unicode.org/versions/Unicode5.1.0/
                     if ((ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) {
                         String intString = Integer.toHexString(ch);
                         sb.append("\\u");
diff --git a/library/src/main/java/com/loopj/android/http/JsonValueInterface.java b/library/src/main/java/com/loopj/android/http/JsonValueInterface.java
index 3d84513a7..e7b013622 100644
--- a/library/src/main/java/com/loopj/android/http/JsonValueInterface.java
+++ b/library/src/main/java/com/loopj/android/http/JsonValueInterface.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java b/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java
index dfc45ec04..80a5eb614 100644
--- a/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java
+++ b/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2014 Aymon Fournier 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java
index 4808bcbf1..f4925f9d9 100755
--- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java
+++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -52,7 +52,7 @@
 
 /**
  * This file is introduced to fix HTTPS Post bug on API < ICS see
- * http://code.google.com/p/android/issues/detail?id=13117#c14 

 

Warning! This omits SSL + * https://code.google.com/p/android/issues/detail?id=13117#c14

 

Warning! This omits SSL * certificate validation on every device, use with caution */ public class MySSLSocketFactory extends SSLSocketFactory { diff --git a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java index 87db21b5d..04708281b 100755 --- a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java +++ b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java index d3832c6da..06abdf0d1 100644 --- a/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java +++ b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index ae1032138..ba8a666c5 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index 1eb3c0d34..3992185c7 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2013 Jason Choy - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 0123d24fe..1536ab2d3 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -87,7 +87,7 @@ * params.put("users", listOfMaps); // url params: "users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female" * * AsyncHttpClient client = new AsyncHttpClient(); - * client.post("http://myendpoint.com/", params, responseHandler); + * client.post("https://myendpoint.com/", params, responseHandler); *
*/ public class RequestParams implements Serializable { diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index fcba44961..82fbc1bc5 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2013 Marek Sebera - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/RetryHandler.java b/library/src/main/java/com/loopj/android/http/RetryHandler.java index 3b6ad1969..7dba7a45f 100755 --- a/library/src/main/java/com/loopj/android/http/RetryHandler.java +++ b/library/src/main/java/com/loopj/android/http/RetryHandler.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index 157b87a3e..fd0a2b58d 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/SerializableCookie.java b/library/src/main/java/com/loopj/android/http/SerializableCookie.java index f7e196c03..ef8895eb7 100755 --- a/library/src/main/java/com/loopj/android/http/SerializableCookie.java +++ b/library/src/main/java/com/loopj/android/http/SerializableCookie.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index 1f3db6b75..cb0462896 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -17,8 +17,8 @@ */ /* - This code is taken from Rafael Sanches' blog. - http://blog.rafaelsanches.com/2011/01/29/upload-using-multipart-post-using-httpclient-in-android/ + This code is taken from Rafael Sanches' blog. Link is no longer working (as of 17th July 2015) + https://blog.rafaelsanches.com/2011/01/29/upload-using-multipart-post-using-httpclient-in-android/ */ package com.loopj.android.http; @@ -298,4 +298,4 @@ public InputStream getContent() throws IOException, UnsupportedOperationExceptio throw new UnsupportedOperationException( "getContent() is not supported. Use writeTo() instead."); } -} \ No newline at end of file +} diff --git a/library/src/main/java/com/loopj/android/http/SyncHttpClient.java b/library/src/main/java/com/loopj/android/http/SyncHttpClient.java index 9626a71cb..6d969134e 100755 --- a/library/src/main/java/com/loopj/android/http/SyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/SyncHttpClient.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java index 1ed7233f6..709123ff1 100755 --- a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java @@ -1,13 +1,13 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - http://loopj.com + https://loopj.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -30,7 +30,7 @@ * {@link #onFinish()} methods as required.

 

For example:

 

*
  * AsyncHttpClient client = new AsyncHttpClient();
- * client.get("http://www.google.com/", new TextHttpResponseHandler() {
+ * client.get("https://www.google.com/", new TextHttpResponseHandler() {
  *     @Override
  *     public void onStart() {
  *         // Initiated the request
diff --git a/library/src/main/java/com/loopj/android/http/Utils.java b/library/src/main/java/com/loopj/android/http/Utils.java
index 196d5a46b..d8311e992 100644
--- a/library/src/main/java/com/loopj/android/http/Utils.java
+++ b/library/src/main/java/com/loopj/android/http/Utils.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/library/src/main/java/com/loopj/android/http/package-info.java b/library/src/main/java/com/loopj/android/http/package-info.java
index 40174b195..7d6224e1e 100644
--- a/library/src/main/java/com/loopj/android/http/package-info.java
+++ b/library/src/main/java/com/loopj/android/http/package-info.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2011 James Smith 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/maven_push.gradle b/maven_push.gradle
index 93f9f4e05..b56473b28 100755
--- a/maven_push.gradle
+++ b/maven_push.gradle
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *     https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
index 15c818e84..f3a9335b5 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java b/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java
index dc3eea3d7..7123b7fe5 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java
index 84d23b5f9..ac69e69ac 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java
index f3c063fa8..25ee6bd0a 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java
index 101a88e72..5266a50e1 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java b/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java
index 621c7f8c9..83ef5c8f7 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -57,7 +57,7 @@ public class CustomCASample extends SampleParentActivity {
     private static final String LOG_TAG = "CustomCASample";
 
     // This is A TEST URL for use with AsyncHttpClient LIBRARY ONLY!
-    // It is provided courtesy of Fineswap (http://fineswap.com) and must never
+    // It is provided courtesy of Fineswap (https://fineswap.com) and must never
     // be used in ANY program except when running this sample (CustomCASample).
     private static final String SERVER_TEST_URL = "https://api.fineswap.io/ahc";
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java b/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java
index 1a5dc4aa9..97d652bf9 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java
index 0ee8a87d4..56bce8948 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/FileSample.java b/sample/src/main/java/com/loopj/android/http/sample/FileSample.java
index 4d774e60f..957cc9fe9 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/FileSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/FileSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java
index ac11151a4..6b13f5a90 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java b/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java
index 3cf000a67..9025a3000 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java
index e70cff4b6..c8bf4d3d4 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java
index d9ed5f3ab..2858e914a 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java
index 295174761..d05cf2233 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java b/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java
index d2e734f46..4c7270de6 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/PostSample.java b/sample/src/main/java/com/loopj/android/http/sample/PostSample.java
index 5cd9138da..234887dc8 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/PostSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/PostSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java
index a2223d02f..2a7c5726c 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/PutSample.java b/sample/src/main/java/com/loopj/android/http/sample/PutSample.java
index 1b43c51f7..f93d383b1 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/PutSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/PutSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java
index 274b5e2bf..21774e595 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -88,7 +88,7 @@ public boolean isRequestHeadersAllowed() {
 
     @Override
     public String getDefaultURL() {
-        return "http://upload.wikimedia.org/wikipedia/commons/f/fa/Geysers_on_Mars.jpg";
+        return "https://upload.wikimedia.org/wikipedia/commons/f/fa/Geysers_on_Mars.jpg";
     }
 
     @Override
diff --git a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java
index 69ce98abd..3a964f357 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java b/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java
index f9d66f6c9..8add61caa 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java b/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java
index 225ff6a71..18cbca1ea 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java
index 1ee17502a..ea4ed26ff 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java
index ca85eb8d6..cb6ec25fb 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java b/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java
index bb92f02c4..3f80ddb76 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java
index 052f03057..3bec476d9 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java
index dc02d306e..ff5a22fea 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/package-info.java b/sample/src/main/java/com/loopj/android/http/sample/package-info.java
index d2d743a5b..c22f5a8d1 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/package-info.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/package-info.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java b/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java
index df4ac428e..c7c54db2b 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java b/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java
index 6838d595a..18f4334df 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,7 +24,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 
-// Source: http://stackoverflow.com/questions/12910503/android-read-file-as-string
+// Source: https://stackoverflow.com/questions/12910503/android-read-file-as-string
 public class FileUtil {
 
     public static String convertStreamToString(InputStream is) throws Exception {
diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java b/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java
index 8e6c4a911..e9f109415 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java
index 8cc05f43a..a6380ccd1 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client Sample
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java b/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java
index 4937f7f56..bc0c7263c 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java
@@ -1,13 +1,13 @@
 /*
     Android Asynchronous Http Client
     Copyright (c) 2014 Marek Sebera 
-    http://loopj.com
+    https://loopj.com
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
 
-        http://www.apache.org/licenses/LICENSE-2.0
+        https://www.apache.org/licenses/LICENSE-2.0
 
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,

From 004fbda2b490e622d1a3994a29ded568996bc5df Mon Sep 17 00:00:00 2001
From: Alashow 
Date: Sun, 19 Jul 2015 20:47:42 +0500
Subject: [PATCH 100/167] Update README.md

---
 README.md | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 2150dedd4..088ac3309 100755
--- a/README.md
+++ b/README.md
@@ -56,7 +56,10 @@ ArtifactId: android-async-http
 Version: 1.4.8
 Packaging: JAR or AAR
 ```
-Gradle: `com.loopj.android:android-async-http:1.4.8`
+Gradle
+```groovy
+compile 'com.loopj.android:android-async-http:1.4.8'
+```
 
 **development snapshots**
 
@@ -68,7 +71,10 @@ ArtifactId: android-async-http
 Version: 1.4.9-SNAPSHOT
 Packaging: JAR or AAR
 ```
-Gradle: `com.loopj.android:android-async-http:1.4.9-SNAPSHOT`
+Gradle`
+```groovy
+compile 'com.loopj.android:android-async-http:1.4.9-SNAPSHOT'
+```
 
 Documentation, Features and Examples
 ------------------------------------

From bfc29dff5fe0989e96474123569271a7e630c710 Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Sun, 19 Jul 2015 20:22:35 +0200
Subject: [PATCH 101/167] Update Gradle/Groovy definition of build dependency

---
 README.md | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 088ac3309..23e29fd66 100755
--- a/README.md
+++ b/README.md
@@ -58,7 +58,14 @@ Packaging: JAR or AAR
 ```
 Gradle
 ```groovy
-compile 'com.loopj.android:android-async-http:1.4.8'
+repositories {
+  maven {
+    mavenCentral()
+  }
+}
+dependencies {
+  compile 'com.loopj.android:android-async-http:1.4.8'
+}
 ```
 
 **development snapshots**
@@ -71,9 +78,16 @@ ArtifactId: android-async-http
 Version: 1.4.9-SNAPSHOT
 Packaging: JAR or AAR
 ```
-Gradle`
+Gradle
 ```groovy
-compile 'com.loopj.android:android-async-http:1.4.9-SNAPSHOT'
+repositories {
+  maven {
+    url 'https://oss.sonatype.org/content/repositories/snapshots/'
+  }
+}
+dependencies {
+  compile 'com.loopj.android:android-async-http:1.4.9-SNAPSHOT'
+}
 ```
 
 Documentation, Features and Examples

From bde3ccd1bc7c6aa48018f3508151fb9e09688dd5 Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Fri, 31 Jul 2015 12:56:24 +0200
Subject: [PATCH 102/167] Gradle Wrapper to provide Sources and Javadoc

---
 gradle/wrapper/gradle-wrapper.properties | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 50080f7e1..3af41f22a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Jul 12 18:36:13 CEST 2015
+#Fri Jul 31 10:35:35 CEST 2015
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip

From 846c831ee469f28b72cf6248e8eb0226fedc9fad Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Fri, 31 Jul 2015 13:03:29 +0200
Subject: [PATCH 103/167] Lint Fixes

---
 .../java/com/loopj/android/http/Base64OutputStream.java   | 2 +-
 .../java/com/loopj/android/http/MySSLSocketFactory.java   | 2 +-
 .../com/loopj/android/http/SimpleMultipartEntity.java     | 8 ++++----
 .../android/http/sample/AsyncBackgroundThreadSample.java  | 2 +-
 .../loopj/android/http/sample/SampleParentActivity.java   | 2 +-
 .../java/com/loopj/android/http/sample/SaxSample.java     | 8 ++++----
 .../http/sample/services/ExampleIntentService.java        | 2 +-
 7 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/library/src/main/java/com/loopj/android/http/Base64OutputStream.java b/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
index aa14ea459..af72f373a 100755
--- a/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
+++ b/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
@@ -27,7 +27,7 @@ public class Base64OutputStream extends FilterOutputStream {
     private byte[] buffer = null;
     private int bpos = 0;
 
-    private static byte[] EMPTY = new byte[0];
+    private static final byte[] EMPTY = new byte[0];
 
     /**
      * Performs Base64 encoding on the data written to the stream, writing the encoded data to
diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java
index f4925f9d9..67d6becc8 100755
--- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java
+++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java
@@ -56,7 +56,7 @@
  * certificate validation on every device, use with caution
  */
 public class MySSLSocketFactory extends SSLSocketFactory {
-    SSLContext sslContext = SSLContext.getInstance("TLS");
+    final SSLContext sslContext = SSLContext.getInstance("TLS");
 
     /**
      * Creates a new SSL Socket Factory with the given KeyStore.
diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java
index cb0462896..1eba09308 100755
--- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java
+++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java
@@ -38,7 +38,7 @@
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Random;
+import java.security.SecureRandom;
 
 /**
  * Simplified multipart entity mainly used for sending one or more files.
@@ -74,7 +74,7 @@ class SimpleMultipartEntity implements HttpEntity {
 
     public SimpleMultipartEntity(ResponseHandlerInterface progressHandler) {
         final StringBuilder buf = new StringBuilder();
-        final Random rand = new Random();
+        final SecureRandom rand = new SecureRandom();
         for (int i = 0; i < 30; i++) {
             buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
         }
@@ -171,8 +171,8 @@ private void updateProgress(long count) {
     }
 
     private class FilePart {
-        public File file;
-        public byte[] header;
+        public final File file;
+        public final byte[] header;
 
         public FilePart(String key, File file, String type, String customFileName) {
             header = createHeader(key, TextUtils.isEmpty(customFileName) ? file.getName() : customFileName, type);
diff --git a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
index f3a9335b5..9ba4d9dde 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
@@ -40,7 +40,7 @@
 public class AsyncBackgroundThreadSample extends SampleParentActivity {
     private static final String LOG_TAG = "AsyncBackgroundThreadSample";
 
-    private ExecutorService executor = Executors.newSingleThreadExecutor();
+    private final ExecutorService executor = Executors.newSingleThreadExecutor();
 
     @Override
     public void onStop()
diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java
index ea4ed26ff..6accb5570 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java
@@ -225,7 +225,7 @@ public void onCancelButtonPressed() {
         asyncHttpClient.cancelRequests(SampleParentActivity.this, true);
     }
 
-    protected View.OnClickListener onClickListener = new View.OnClickListener() {
+    protected final View.OnClickListener onClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             switch (v.getId()) {
diff --git a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java
index cb6ec25fb..aa22c0b1c 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java
@@ -40,7 +40,7 @@ public ResponseHandlerInterface getResponseHandler() {
         return saxAsyncHttpResponseHandler;
     }
 
-    private SaxAsyncHttpResponseHandler saxAsyncHttpResponseHandler = new SaxAsyncHttpResponseHandler(new SAXTreeStructure()) {
+    private final SaxAsyncHttpResponseHandler saxAsyncHttpResponseHandler = new SaxAsyncHttpResponseHandler(new SAXTreeStructure()) {
         @Override
         public void onStart() {
             clearOutputs();
@@ -93,8 +93,8 @@ public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[]
     }
 
     private class Tuple {
-        public Integer color;
-        public String text;
+        public final Integer color;
+        public final String text;
 
         public Tuple(int _color, String _text) {
             this.color = _color;
@@ -104,7 +104,7 @@ public Tuple(int _color, String _text) {
 
     private class SAXTreeStructure extends DefaultHandler {
 
-        public List responseViews = new ArrayList();
+        public final List responseViews = new ArrayList();
 
         public void startElement(String namespaceURI, String localName,
                                  String rawName, Attributes atts) {
diff --git a/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java b/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java
index 7fe49c71e..63e2ede27 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java
@@ -21,7 +21,7 @@ public class ExampleIntentService extends IntentService {
     public static final String INTENT_DATA = "INTENT_DATA";
     public static final String INTENT_THROWABLE = "INTENT_THROWABLE";
 
-    private AsyncHttpClient aClient = new SyncHttpClient();
+    private final AsyncHttpClient aClient = new SyncHttpClient();
 
     public ExampleIntentService() {
         super("ExampleIntentService");

From d21cb9ff85a16ca25fe3fd72f563da55e68a0b2c Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Fri, 31 Jul 2015 13:27:44 +0200
Subject: [PATCH 104/167] Reverting Lint fix for Random->SecureRandom

---
 .../java/com/loopj/android/http/SimpleMultipartEntity.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java
index 1eba09308..541b3d5a7 100755
--- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java
+++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java
@@ -38,7 +38,7 @@
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
-import java.security.SecureRandom;
+import java.util.Random;
 
 /**
  * Simplified multipart entity mainly used for sending one or more files.
@@ -74,7 +74,7 @@ class SimpleMultipartEntity implements HttpEntity {
 
     public SimpleMultipartEntity(ResponseHandlerInterface progressHandler) {
         final StringBuilder buf = new StringBuilder();
-        final SecureRandom rand = new SecureRandom();
+        final Random rand = new Random();
         for (int i = 0; i < 30; i++) {
             buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
         }

From 2f4d1d8ad4bb4a1f531a57487601668b3527758c Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Mon, 24 Aug 2015 10:41:08 +0200
Subject: [PATCH 105/167] Compatibility for API 23 with library
 'org.apache.http.legacy'

---
 build.gradle         | 2 +-
 library/build.gradle | 7 ++++---
 sample/build.gradle  | 9 +++++----
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/build.gradle b/build.gradle
index 97d2df08a..d270e5727 100755
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ buildscript {
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.2.3'
+        classpath 'com.android.tools.build:gradle:1.3.1'
     }
 }
 
diff --git a/library/build.gradle b/library/build.gradle
index 31d250041..9b975a19d 100755
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -1,12 +1,13 @@
 apply plugin: 'com.android.library'
 
 android {
-    compileSdkVersion 22
-    buildToolsVersion '22.0.1'
+    compileSdkVersion 23
+    buildToolsVersion '23.0.0'
+    useLibrary 'org.apache.http.legacy'
 
     defaultConfig {
         minSdkVersion 3
-        targetSdkVersion 22
+        targetSdkVersion 23
     }
 
     lintOptions {
diff --git a/sample/build.gradle b/sample/build.gradle
index 9ddfff4f3..749a8118d 100755
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -8,12 +8,13 @@ repositories {
 }
 
 android {
-    compileSdkVersion 22
-    buildToolsVersion '22.0.1'
+    compileSdkVersion 23
+    buildToolsVersion '23.0.0'
+    useLibrary 'org.apache.http.legacy'
 
     defaultConfig {
         minSdkVersion 3
-        targetSdkVersion 22
+        targetSdkVersion 23
     }
 
     productFlavors {
@@ -21,7 +22,7 @@ android {
         }
         withLeakCanary {
             minSdkVersion 8
-            targetSdkVersion 22
+            targetSdkVersion 23
         }
     }
 

From dc184805534a66076b995f2c6f6373b13aeada76 Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Mon, 24 Aug 2015 10:46:03 +0200
Subject: [PATCH 106/167] Fixed GZIP decoding for streams that are not yet read
 up to 2 bytes, #830

---
 .../src/main/java/com/loopj/android/http/AsyncHttpClient.java  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java
index b9ee31352..b10ea6f2c 100755
--- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java
+++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java
@@ -1608,7 +1608,8 @@ public InflatingEntity(HttpEntity wrapped) {
         public InputStream getContent() throws IOException {
             wrappedStream = wrappedEntity.getContent();
             pushbackStream = new PushbackInputStream(wrappedStream, 2);
-            if (isInputStreamGZIPCompressed(pushbackStream)) {
+            Header enc = wrappedEntity.getContentEncoding();
+            if ((enc != null && "gzip".equalsIgnoreCase(enc.getValue())) || isInputStreamGZIPCompressed(pushbackStream)) {
                 gzippedStream = new GZIPInputStream(pushbackStream);
                 return gzippedStream;
             } else {

From 6109777a18585125673e0fdaa232dd41ecc410f1 Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Mon, 24 Aug 2015 10:51:51 +0200
Subject: [PATCH 107/167] Fix Travis CI

---
 .travis.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index ff2abb9d3..ebb94b22f 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,10 +2,10 @@ language: android
 jdk: openjdk7
 android:
   components:
-    - build-tools-22.0.1
+    - build-tools-23.0.0
     - extra-android-support
     - extra-android-m2repository
-    - android-22
+    - android-23
   licenses:
     - '.+'
 script:

From 00165f400627b38da77740aa48660096fd77a34e Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Mon, 24 Aug 2015 11:02:06 +0200
Subject: [PATCH 108/167] Lint issue with API23 fixed

---
 library/src/main/AndroidManifest.xml | 2 --
 sample/src/main/AndroidManifest.xml  | 1 +
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
index 3049b2d68..33c5bc133 100755
--- a/library/src/main/AndroidManifest.xml
+++ b/library/src/main/AndroidManifest.xml
@@ -4,6 +4,4 @@
 
     
 
-    
-
  
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
index e6fee30c9..8f3e351f9 100755
--- a/sample/src/main/AndroidManifest.xml
+++ b/sample/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
     

From 15f9556b578dbf247ff32032461b094d4bfd31a9 Mon Sep 17 00:00:00 2001
From: Marek Sebera 
Date: Sat, 12 Sep 2015 17:53:15 +0200
Subject: [PATCH 109/167] Dependency added, build script updated, renamed all
 org.apache.http dependency to cz.msebera.android.httpclient

---
 .travis.yml                                   |   2 +-
 build.gradle                                  |   1 +
 library/build.gradle                          |   7 +-
 library/src/main/AndroidManifest.xml          |   4 +-
 .../loopj/android/http/AsyncHttpClient.java   | 527 +++++++++---------
 .../loopj/android/http/AsyncHttpRequest.java  |  14 +-
 .../http/AsyncHttpResponseHandler.java        |  85 ++-
 .../java/com/loopj/android/http/Base64.java   | 266 +++++----
 .../android/http/Base64OutputStream.java      |   4 +-
 .../http/BaseJsonHttpResponseHandler.java     |   6 +-
 .../http/BinaryHttpResponseHandler.java       |  58 +-
 .../http/BlackholeHttpResponseHandler.java    |   4 +-
 .../http/DataAsyncHttpResponseHandler.java    |  70 ++-
 .../http/FileAsyncHttpResponseHandler.java    |   8 +-
 .../com/loopj/android/http/HttpDelete.java    |   4 +-
 .../java/com/loopj/android/http/HttpGet.java  |   4 +-
 .../com/loopj/android/http/HttpPatch.java     |   4 +-
 .../android/http/JsonHttpResponseHandler.java |   9 +-
 .../android/http/JsonStreamerEntity.java      | 141 +++--
 .../loopj/android/http/MyRedirectHandler.java |  30 +-
 .../android/http/MySSLSocketFactory.java      |  60 +-
 .../android/http/PersistentCookieStore.java   |   9 +-
 ...veAuthorizationHttpRequestInterceptor.java |  26 +-
 .../RangeFileAsyncHttpResponseHandler.java    |  16 +-
 .../com/loopj/android/http/RequestHandle.java |  20 +-
 .../com/loopj/android/http/RequestParams.java |  76 +--
 .../http/ResponseHandlerInterface.java        |  54 +-
 .../com/loopj/android/http/RetryHandler.java  |  28 +-
 .../http/SaxAsyncHttpResponseHandler.java     |   9 +-
 .../android/http/SerializableCookie.java      |   6 +-
 .../android/http/SimpleMultipartEntity.java   | 128 +++--
 .../loopj/android/http/SyncHttpClient.java    |   8 +-
 .../android/http/TextHttpResponseHandler.java |  48 +-
 sample/build.gradle                           |   3 +-
 .../sample/AsyncBackgroundThreadSample.java   |   9 +-
 .../android/http/sample/BinarySample.java     |   4 +-
 .../http/sample/CancelRequestByTagSample.java |   4 +-
 .../ContentTypeForHttpEntitySample.java       |   6 +-
 .../android/http/sample/CustomCASample.java   |  18 +-
 .../android/http/sample/DeleteSample.java     |   4 +-
 .../android/http/sample/DigestAuthSample.java |   8 +-
 .../android/http/sample/DirectorySample.java  |   6 +-
 .../loopj/android/http/sample/FileSample.java |   6 +-
 .../android/http/sample/FilesSample.java      |   6 +-
 .../loopj/android/http/sample/GetSample.java  |   4 +-
 .../http/sample/Http401AuthSample.java        |   8 +-
 .../http/sample/IntentServiceSample.java      |  16 +-
 .../loopj/android/http/sample/JsonSample.java |   4 +-
 .../http/sample/JsonStreamerSample.java       |   7 +-
 .../android/http/sample/PatchSample.java      |  60 +-
 .../http/sample/PersistentCookiesSample.java  |   9 +-
 .../loopj/android/http/sample/PostSample.java |   4 +-
 .../http/sample/PrePostProcessingSample.java  |  31 +-
 .../loopj/android/http/sample/PutSample.java  |   4 +-
 .../http/sample/RangeResponseSample.java      |  10 +-
 .../http/sample/Redirect302Sample.java        |  11 +-
 .../http/sample/RequestParamsDebug.java       |   8 +-
 .../http/sample/ResumeDownloadSample.java     |   8 +-
 .../http/sample/RetryRequestSample.java       |  13 +-
 .../android/http/sample/SampleInterface.java  |  13 +-
 .../http/sample/SampleParentActivity.java     |  99 ++--
 .../loopj/android/http/sample/SaxSample.java  |  16 +-
 .../http/sample/SynchronousClientSample.java  |   4 +-
 .../http/sample/ThreadingTimeoutSample.java   |   4 +-
 .../http/sample/UsePoolThreadSample.java      |   4 +-
 .../sample/services/ExampleIntentService.java |   2 +-
 .../android/http/sample/util/IntentUtil.java  |   4 +-
 .../http/sample/util/SecureSocketFactory.java |   8 +-
 .../src/main/res/layout-v14/parent_layout.xml |  27 +-
 sample/src/main/res/layout/credentials.xml    |  80 ++-
 sample/src/main/res/layout/parent_layout.xml  |  33 +-
 71 files changed, 1136 insertions(+), 1165 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index ebb94b22f..92617b894 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ language: android
 jdk: openjdk7
 android:
   components:
-    - build-tools-23.0.0
+    - build-tools-23.0.1
     - extra-android-support
     - extra-android-m2repository
     - android-23
diff --git a/build.gradle b/build.gradle
index d270e5727..f1b4276ac 100755
--- a/build.gradle
+++ b/build.gradle
@@ -17,6 +17,7 @@ allprojects {
     version = '1.4.9-SNAPSHOT'
 
     repositories {
+        mavenLocal()
         mavenCentral()
     }
 
diff --git a/library/build.gradle b/library/build.gradle
index 9b975a19d..b1c33c2fe 100755
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -2,8 +2,7 @@ apply plugin: 'com.android.library'
 
 android {
     compileSdkVersion 23
-    buildToolsVersion '23.0.0'
-    useLibrary 'org.apache.http.legacy'
+    buildToolsVersion '23.0.1'
 
     defaultConfig {
         minSdkVersion 3
@@ -24,6 +23,10 @@ android {
     }
 }
 
+dependencies {
+    compile 'cz.msebera.android:httpclient:4.3.3'
+}
+
 android.libraryVariants.all { variant ->
     def name = variant.buildType.name
     def task = project.tasks.create "jar${name.capitalize()}", Jar
diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
index 33c5bc133..7af3e5711 100755
--- a/library/src/main/AndroidManifest.xml
+++ b/library/src/main/AndroidManifest.xml
@@ -1,7 +1,7 @@
 
 
+    package="com.loopj.android.http">
 
-    
+    
 
  
diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java
index b10ea6f2c..d1e63fc8b 100755
--- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java
+++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java
@@ -21,52 +21,6 @@
 import android.content.Context;
 import android.os.Looper;
 
-import org.apache.http.Header;
-import org.apache.http.HeaderElement;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpResponseInterceptor;
-import org.apache.http.HttpVersion;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.AuthState;
-import org.apache.http.auth.Credentials;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.CookieStore;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.RedirectHandler;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.params.ClientPNames;
-import org.apache.http.client.protocol.ClientContext;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.params.ConnManagerParams;
-import org.apache.http.conn.params.ConnPerRouteBean;
-import org.apache.http.conn.params.ConnRoutePNames;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.entity.HttpEntityWrapper;
-import org.apache.http.impl.auth.BasicScheme;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.SyncBasicHttpContext;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -86,6 +40,52 @@
 import java.util.concurrent.Executors;
 import java.util.zip.GZIPInputStream;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HeaderElement;
+import cz.msebera.android.httpclient.HttpEntity;
+import cz.msebera.android.httpclient.HttpException;
+import cz.msebera.android.httpclient.HttpHost;
+import cz.msebera.android.httpclient.HttpRequest;
+import cz.msebera.android.httpclient.HttpRequestInterceptor;
+import cz.msebera.android.httpclient.HttpResponse;
+import cz.msebera.android.httpclient.HttpResponseInterceptor;
+import cz.msebera.android.httpclient.HttpVersion;
+import cz.msebera.android.httpclient.auth.AuthScope;
+import cz.msebera.android.httpclient.auth.AuthState;
+import cz.msebera.android.httpclient.auth.Credentials;
+import cz.msebera.android.httpclient.auth.UsernamePasswordCredentials;
+import cz.msebera.android.httpclient.client.CookieStore;
+import cz.msebera.android.httpclient.client.CredentialsProvider;
+import cz.msebera.android.httpclient.client.HttpClient;
+import cz.msebera.android.httpclient.client.RedirectHandler;
+import cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase;
+import cz.msebera.android.httpclient.client.methods.HttpHead;
+import cz.msebera.android.httpclient.client.methods.HttpPost;
+import cz.msebera.android.httpclient.client.methods.HttpPut;
+import cz.msebera.android.httpclient.client.methods.HttpUriRequest;
+import cz.msebera.android.httpclient.client.params.ClientPNames;
+import cz.msebera.android.httpclient.client.protocol.ClientContext;
+import cz.msebera.android.httpclient.conn.ClientConnectionManager;
+import cz.msebera.android.httpclient.conn.params.ConnManagerParams;
+import cz.msebera.android.httpclient.conn.params.ConnPerRouteBean;
+import cz.msebera.android.httpclient.conn.params.ConnRoutePNames;
+import cz.msebera.android.httpclient.conn.scheme.PlainSocketFactory;
+import cz.msebera.android.httpclient.conn.scheme.Scheme;
+import cz.msebera.android.httpclient.conn.scheme.SchemeRegistry;
+import cz.msebera.android.httpclient.conn.ssl.SSLSocketFactory;
+import cz.msebera.android.httpclient.entity.HttpEntityWrapper;
+import cz.msebera.android.httpclient.impl.auth.BasicScheme;
+import cz.msebera.android.httpclient.impl.client.DefaultHttpClient;
+import cz.msebera.android.httpclient.impl.conn.tsccm.ThreadSafeClientConnManager;
+import cz.msebera.android.httpclient.params.BasicHttpParams;
+import cz.msebera.android.httpclient.params.HttpConnectionParams;
+import cz.msebera.android.httpclient.params.HttpParams;
+import cz.msebera.android.httpclient.params.HttpProtocolParams;
+import cz.msebera.android.httpclient.protocol.BasicHttpContext;
+import cz.msebera.android.httpclient.protocol.ExecutionContext;
+import cz.msebera.android.httpclient.protocol.HttpContext;
+import cz.msebera.android.httpclient.protocol.SyncBasicHttpContext;
+
 
 /**
  * The AsyncHttpClient can be used to make asynchronous GET, POST, PUT and DELETE HTTP requests in
@@ -128,20 +128,17 @@ public class AsyncHttpClient {
     public static final int DEFAULT_MAX_RETRIES = 5;
     public static final int DEFAULT_RETRY_SLEEP_TIME_MILLIS = 1500;
     public static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192;
-
-    private int maxConnections = DEFAULT_MAX_CONNECTIONS;
-    private int connectTimeout = DEFAULT_SOCKET_TIMEOUT;
-    private int responseTimeout = DEFAULT_SOCKET_TIMEOUT;
-
+    public static LogInterface log = new LogHandler();
     private final DefaultHttpClient httpClient;
     private final HttpContext httpContext;
-    private ExecutorService threadPool;
     private final Map> requestMap;
     private final Map clientHeaderMap;
+    private int maxConnections = DEFAULT_MAX_CONNECTIONS;
+    private int connectTimeout = DEFAULT_SOCKET_TIMEOUT;
+    private int responseTimeout = DEFAULT_SOCKET_TIMEOUT;
+    private ExecutorService threadPool;
     private boolean isUrlEncodingEnabled = true;
 
-    public static LogInterface log = new LogHandler();
-
     /**
      * Creates a new AsyncHttpClient with default constructor arguments values
      */
@@ -179,44 +176,6 @@ public AsyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int htt
         this(getDefaultSchemeRegistry(fixNoHttpResponseException, httpPort, httpsPort));
     }
 
-    /**
-     * Returns default instance of SchemeRegistry
-     *
-     * @param fixNoHttpResponseException Whether to fix issue or not, by omitting SSL verification
-     * @param httpPort                   HTTP port to be used, must be greater than 0
-     * @param httpsPort                  HTTPS port to be used, must be greater than 0
-     */
-    private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
-        if (fixNoHttpResponseException) {
-            log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates.");
-        }
-
-        if (httpPort < 1) {
-            httpPort = 80;
-            log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80");
-        }
-
-        if (httpsPort < 1) {
-            httpsPort = 443;
-            log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443");
-        }
-
-        // Fix to SSL flaw in API < ICS
-        // See https://code.google.com/p/android/issues/detail?id=13117
-        SSLSocketFactory sslSocketFactory;
-        if (fixNoHttpResponseException) {
-            sslSocketFactory = MySSLSocketFactory.getFixedSocketFactory();
-        } else {
-            sslSocketFactory = SSLSocketFactory.getSocketFactory();
-        }
-
-        SchemeRegistry schemeRegistry = new SchemeRegistry();
-        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), httpPort));
-        schemeRegistry.register(new Scheme("https", sslSocketFactory, httpsPort));
-
-        return schemeRegistry;
-    }
-
     /**
      * Creates a new AsyncHttpClient.
      *
@@ -310,6 +269,44 @@ public void process(final HttpRequest request, final HttpContext context) throws
         httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));
     }
 
+    /**
+     * Returns default instance of SchemeRegistry
+     *
+     * @param fixNoHttpResponseException Whether to fix issue or not, by omitting SSL verification
+     * @param httpPort                   HTTP port to be used, must be greater than 0
+     * @param httpsPort                  HTTPS port to be used, must be greater than 0
+     */
+    private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
+        if (fixNoHttpResponseException) {
+            log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates.");
+        }
+
+        if (httpPort < 1) {
+            httpPort = 80;
+            log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80");
+        }
+
+        if (httpsPort < 1) {
+            httpsPort = 443;
+            log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443");
+        }
+
+        // Fix to SSL flaw in API < ICS
+        // See https://code.google.com/p/android/issues/detail?id=13117
+        SSLSocketFactory sslSocketFactory;
+        if (fixNoHttpResponseException) {
+            sslSocketFactory = MySSLSocketFactory.getFixedSocketFactory();
+        } else {
+            sslSocketFactory = SSLSocketFactory.getSocketFactory();
+        }
+
+        SchemeRegistry schemeRegistry = new SchemeRegistry();
+        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), httpPort));
+        schemeRegistry.register(new Scheme("https", sslSocketFactory, httpsPort));
+
+        return schemeRegistry;
+    }
+
     public static void allowRetryExceptionClass(Class cls) {
         if (cls != null) {
             RetryHandler.addClassToWhitelist(cls);
@@ -322,6 +319,124 @@ public static void blockRetryExceptionClass(Class cls) {
         }
     }
 
+    /**
+     * Will encode url, if not disabled, and adds params on the end of it
+     *
+     * @param url             String with URL, should be valid URL without params
+     * @param params          RequestParams to be appended on the end of URL
+     * @param shouldEncodeUrl whether url should be encoded (replaces spaces with %20)
+     * @return encoded url if requested with params appended if any available
+     */
+    public static String getUrlWithQueryString(boolean shouldEncodeUrl, String url, RequestParams params) {
+        if (url == null)
+            return null;
+
+        if (shouldEncodeUrl) {
+            try {
+                String decodedURL = URLDecoder.decode(url, "UTF-8");
+                URL _url = new URL(decodedURL);
+                URI _uri = new URI(_url.getProtocol(), _url.getUserInfo(), _url.getHost(), _url.getPort(), _url.getPath(), _url.getQuery(), _url.getRef());
+                url = _uri.toASCIIString();
+            } catch (Exception ex) {
+                // Should not really happen, added just for sake of validity
+                log.e(LOG_TAG, "getUrlWithQueryString encoding URL", ex);
+            }
+        }
+
+        if (params != null) {
+            // Construct the query string and trim it, in case it
+            // includes any excessive white spaces.
+            String paramString = params.getParamString().trim();
+
+            // Only add the query string if it isn't empty and it
+            // isn't equal to '?'.
+            if (!paramString.equals("") && !paramString.equals("?")) {
+                url += url.contains("?") ? "&" : "?";
+                url += paramString;
+            }
+        }
+
+        return url;
+    }
+
+    /**
+     * Checks the InputStream if it contains  GZIP compressed data
+     *
+     * @param inputStream InputStream to be checked
+     * @return true or false if the stream contains GZIP compressed data
+     * @throws java.io.IOException if read from inputStream fails
+     */
+    public static boolean isInputStreamGZIPCompressed(final PushbackInputStream inputStream) throws IOException {
+        if (inputStream == null)
+            return false;
+
+        byte[] signature = new byte[2];
+        int readStatus = inputStream.read(signature);
+        inputStream.unread(signature);
+        int streamHeader = ((int) signature[0] & 0xff) | ((signature[1] << 8) & 0xff00);
+        return readStatus == 2 && GZIPInputStream.GZIP_MAGIC == streamHeader;
+    }
+
+    /**
+     * A utility function to close an input stream without raising an exception.
+     *
+     * @param is input stream to close safely
+     */
+    public static void silentCloseInputStream(InputStream is) {
+        try {
+            if (is != null) {
+                is.close();
+            }
+        } catch (IOException e) {
+            log.w(LOG_TAG, "Cannot close input stream", e);
+        }
+    }
+
+    /**
+     * A utility function to close an output stream without raising an exception.
+     *
+     * @param os output stream to close safely
+     */
+    public static void silentCloseOutputStream(OutputStream os) {
+        try {
+            if (os != null) {
+                os.close();
+            }
+        } catch (IOException e) {
+            log.w(LOG_TAG, "Cannot close output stream", e);
+        }
+    }
+
+    /**
+     * This horrible hack is required on Android, due to implementation of BasicManagedEntity, which
+     * doesn't chain call consumeContent on underlying wrapped HttpEntity
+     *
+     * @param entity HttpEntity, may be null
+     */
+    public static void endEntityViaReflection(HttpEntity entity) {
+        if (entity instanceof HttpEntityWrapper) {
+            try {
+                Field f = null;
+                Field[] fields = HttpEntityWrapper.class.getDeclaredFields();
+                for (Field ff : fields) {
+                    if (ff.getName().equals("wrappedEntity")) {
+                        f = ff;
+                        break;
+                    }
+                }
+                if (f != null) {
+                    f.setAccessible(true);
+                    HttpEntity wrapped = (HttpEntity) f.get(entity);
+                    if (wrapped != null) {
+                        wrapped.consumeContent();
+                    }
+                }
+            } catch (Throwable t) {
+                log.e(LOG_TAG, "wrappedEntity consume", t);
+            }
+        }
+    }
+
     /**
      * Get the underlying HttpClient instance. This is useful for setting additional fine-grained
      * settings for requests by accessing the client's ConnectionManager, HttpParams and
@@ -343,16 +458,6 @@ public HttpContext getHttpContext() {
         return this.httpContext;
     }
 
-    /**
-     * Will set logging enabled flag on underlying LogInterface instance.
-     * Default setting is logging enabled.
-     *
-     * @param loggingEnabled whether the logging should be enabled or not
-     */
-    public void setLoggingEnabled(boolean loggingEnabled) {
-        log.setLoggingEnabled(loggingEnabled);
-    }
-
     /**
      * Returns logging enabled flag from underlying LogInterface instance
      * Default setting is logging enabled.
@@ -364,13 +469,13 @@ public boolean isLoggingEnabled() {
     }
 
     /**
-     * Sets log level to be used across all library default implementation
-     * Default setting is VERBOSE log level.
+     * Will set logging enabled flag on underlying LogInterface instance.
+     * Default setting is logging enabled.
      *
-     * @param logLevel int log level, either from LogInterface interface or from {@link android.util.Log}
+     * @param loggingEnabled whether the logging should be enabled or not
      */
-    public void setLoggingLevel(int logLevel) {
-        log.setLoggingLevel(logLevel);
+    public void setLoggingEnabled(boolean loggingEnabled) {
+        log.setLoggingEnabled(loggingEnabled);
     }
 
     /**
@@ -383,6 +488,16 @@ public int getLoggingLevel() {
         return log.getLoggingLevel();
     }
 
+    /**
+     * Sets log level to be used across all library default implementation
+     * Default setting is VERBOSE log level.
+     *
+     * @param logLevel int log level, either from LogInterface interface or from {@link android.util.Log}
+     */
+    public void setLoggingLevel(int logLevel) {
+        log.setLoggingLevel(logLevel);
+    }
+
     /**
      * Will return current LogInterface used in AsyncHttpClient instance
      *
@@ -414,6 +529,16 @@ public void setCookieStore(CookieStore cookieStore) {
         httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
     }
 
+    /**
+     * Returns the current executor service used. By default, Executors.newCachedThreadPool() is
+     * used.
+     *
+     * @return current executor service used
+     */
+    public ExecutorService getThreadPool() {
+        return threadPool;
+    }
+
     /**
      * Overrides the threadpool implementation used when queuing/pooling requests. By default,
      * Executors.newCachedThreadPool() is used.
@@ -425,16 +550,6 @@ public void setThreadPool(ExecutorService threadPool) {
         this.threadPool = threadPool;
     }
 
-    /**
-     * Returns the current executor service used. By default, Executors.newCachedThreadPool() is
-     * used.
-     *
-     * @return current executor service used
-     */
-    public ExecutorService getThreadPool() {
-        return threadPool;
-    }
-
     /**
      * Get the default threading pool to be used for this HTTP client.
      *
@@ -510,7 +625,6 @@ public void setUserAgent(String userAgent) {
         HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent);
     }
 
-
     /**
      * Returns current limit of parallel connections
      *
@@ -740,6 +854,8 @@ public void setAuthenticationPreemptive(boolean isPreemptive) {
         }
     }
 
+    // [+] HTTP HEAD
+
     /**
      * Removes previously set auth credentials
      */
@@ -831,7 +947,8 @@ public void cancelRequestsByTAG(Object TAG, boolean mayInterruptIfRunning) {
         }
     }
 
-    // [+] HTTP HEAD
+    // [-] HTTP HEAD
+    // [+] HTTP GET
 
     /**
      * Perform a HTTP HEAD request, without any parameters.
@@ -900,9 +1017,6 @@ public RequestHandle head(Context context, String url, Header[] headers, Request
                 context);
     }
 
-    // [-] HTTP HEAD
-    // [+] HTTP GET
-
     /**
      * Perform a HTTP GET request, without any parameters.
      *
@@ -914,6 +1028,9 @@ public RequestHandle get(String url, ResponseHandlerInterface responseHandler) {
         return get(null, url, null, responseHandler);
     }
 
+    // [-] HTTP GET
+    // [+] HTTP POST
+
     /**
      * Perform a HTTP GET request with parameters.
      *
@@ -975,9 +1092,9 @@ public RequestHandle get(Context context, String url, Header[] headers, RequestP
      *
      * @param context         the Android Context which initiated the request.
      * @param url             the URL to send the request to.
-     * @param entity          a raw {@link org.apache.http.HttpEntity} to send with the request, for
+     * @param entity          a raw {@link cz.msebera.android.httpclient.HttpEntity} to send with the request, for
      *                        example, use this to send string/json/xml payloads to a server by
-     *                        passing a {@link org.apache.http.entity.StringEntity}.
+     *                        passing a {@link cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response ha   ndler instance that should handle the response.
@@ -987,9 +1104,6 @@ public RequestHandle get(Context context, String url, HttpEntity entity, String
         return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpGet(URI.create(url).normalize()), entity), contentType, responseHandler, context);
     }
 
-    // [-] HTTP GET
-    // [+] HTTP POST
-
     /**
      * Perform a HTTP POST request, without any parameters.
      *
@@ -1001,6 +1115,9 @@ public RequestHandle post(String url, ResponseHandlerInterface responseHandler)
         return post(null, url, null, responseHandler);
     }
 
+    // [-] HTTP POST
+    // [+] HTTP PUT
+
     /**
      * Perform a HTTP POST request with parameters.
      *
@@ -1031,9 +1148,9 @@ public RequestHandle post(Context context, String url, RequestParams params, Res
      *
      * @param context         the Android Context which initiated the request.
      * @param url             the URL to send the request to.
-     * @param entity          a raw {@link org.apache.http.HttpEntity} to send with the request, for
+     * @param entity          a raw {@link cz.msebera.android.httpclient.HttpEntity} to send with the request, for
      *                        example, use this to send string/json/xml payloads to a server by
-     *                        passing a {@link org.apache.http.entity.StringEntity}.
+     *                        passing a {@link cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response ha   ndler instance that should handle the response.
@@ -1074,7 +1191,7 @@ public RequestHandle post(Context context, String url, Header[] headers, Request
      * @param headers         set headers only for this request
      * @param entity          a raw {@link HttpEntity} to send with the request, for example, use
      *                        this to send string/json/xml payloads to a server by passing a {@link
-     *                        org.apache.http.entity.StringEntity}.
+     *                        cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response handler instance that should handle the response.
@@ -1087,9 +1204,6 @@ public RequestHandle post(Context context, String url, Header[] headers, HttpEnt
         return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context);
     }
 
-    // [-] HTTP POST
-    // [+] HTTP PUT
-
     /**
      * Perform a HTTP PUT request, without any parameters.
      *
@@ -1134,7 +1248,7 @@ public RequestHandle put(Context context, String url, RequestParams params, Resp
      * @param url             the URL to send the request to.
      * @param entity          a raw {@link HttpEntity} to send with the request, for example, use
      *                        this to send string/json/xml payloads to a server by passing a {@link
-     *                        org.apache.http.entity.StringEntity}.
+     *                        cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response handler instance that should handle the response.
@@ -1153,7 +1267,7 @@ public RequestHandle put(Context context, String url, HttpEntity entity, String
      * @param headers         set one-time headers for this request
      * @param entity          a raw {@link HttpEntity} to send with the request, for example, use
      *                        this to send string/json/xml payloads to a server by passing a {@link
-     *                        org.apache.http.entity.StringEntity}.
+     *                        cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response handler instance that should handle the response.
@@ -1165,6 +1279,9 @@ public RequestHandle put(Context context, String url, Header[] headers, HttpEnti
         return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context);
     }
 
+    // [-] HTTP PUT
+    // [+] HTTP DELETE
+
     /**
      * Perform a HTTP
      * request, without any parameters.
@@ -1210,7 +1327,7 @@ public RequestHandle patch(Context context, String url, RequestParams params, Re
      * @param responseHandler the response handler instance that should handle the response.
      * @param entity          a raw {@link HttpEntity} to send with the request, for example, use
      *                        this to send string/json/xml payloads to a server by passing a {@link
-     *                        org.apache.http.entity.StringEntity}
+     *                        cz.msebera.android.httpclient.entity.StringEntity}
      * @param contentType     the content type of the payload you are sending, for example
      *                        "application/json" if sending a json payload.
      * @return RequestHandle of future request process
@@ -1228,7 +1345,7 @@ public RequestHandle patch(Context context, String url, HttpEntity entity, Strin
      * @param headers         set one-time headers for this request
      * @param entity          a raw {@link HttpEntity} to send with the request, for example, use
      *                        this to send string/json/xml payloads to a server by passing a {@link
-     *                        org.apache.http.entity.StringEntity}.
+     *                        cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response handler instance that should handle the response.
@@ -1240,9 +1357,6 @@ public RequestHandle patch(Context context, String url, Header[] headers, HttpEn
         return sendRequest(httpClient, httpContext, request, contentType, responseHandler, context);
     }
 
-    // [-] HTTP PUT
-    // [+] HTTP DELETE
-
     /**
      * Perform a HTTP DELETE request.
      *
@@ -1254,6 +1368,8 @@ public RequestHandle delete(String url, ResponseHandlerInterface responseHandler
         return delete(null, url, responseHandler);
     }
 
+    // [-] HTTP DELETE
+
     /**
      * Perform a HTTP DELETE request.
      *
@@ -1315,9 +1431,9 @@ public RequestHandle delete(Context context, String url, Header[] headers, Reque
      *
      * @param context         the Android Context which initiated the request.
      * @param url             the URL to send the request to.
-     * @param entity          a raw {@link org.apache.http.HttpEntity} to send with the request, for
+     * @param entity          a raw {@link cz.msebera.android.httpclient.HttpEntity} to send with the request, for
      *                        example, use this to send string/json/xml payloads to a server by
-     *                        passing a {@link org.apache.http.entity.StringEntity}.
+     *                        passing a {@link cz.msebera.android.httpclient.entity.StringEntity}.
      * @param contentType     the content type of the payload you are sending, for example
      *                        application/json if sending a json payload.
      * @param responseHandler the response ha   ndler instance that should handle the response.
@@ -1327,8 +1443,6 @@ public RequestHandle delete(Context context, String url, HttpEntity entity, Stri
         return sendRequest(httpClient, httpContext, addEntityToRequestBase(new HttpDelete(URI.create(url).normalize()), entity), contentType, responseHandler, context);
     }
 
-    // [-] HTTP DELETE
-
     /**
      * Instantiate a new asynchronous HTTP request for the passed parameters.
      *
@@ -1429,94 +1543,6 @@ public void setURLEncodingEnabled(boolean enabled) {
         this.isUrlEncodingEnabled = enabled;
     }
 
-    /**
-     * Will encode url, if not disabled, and adds params on the end of it
-     *
-     * @param url             String with URL, should be valid URL without params
-     * @param params          RequestParams to be appended on the end of URL
-     * @param shouldEncodeUrl whether url should be encoded (replaces spaces with %20)
-     * @return encoded url if requested with params appended if any available
-     */
-    public static String getUrlWithQueryString(boolean shouldEncodeUrl, String url, RequestParams params) {
-        if (url == null)
-            return null;
-
-        if (shouldEncodeUrl) {
-            try {
-                String decodedURL = URLDecoder.decode(url, "UTF-8");
-                URL _url = new URL(decodedURL);
-                URI _uri = new URI(_url.getProtocol(), _url.getUserInfo(), _url.getHost(), _url.getPort(), _url.getPath(), _url.getQuery(), _url.getRef());
-                url = _uri.toASCIIString();
-            } catch (Exception ex) {
-                // Should not really happen, added just for sake of validity
-                log.e(LOG_TAG, "getUrlWithQueryString encoding URL", ex);
-            }
-        }
-
-        if (params != null) {
-            // Construct the query string and trim it, in case it
-            // includes any excessive white spaces.
-            String paramString = params.getParamString().trim();
-
-            // Only add the query string if it isn't empty and it
-            // isn't equal to '?'.
-            if (!paramString.equals("") && !paramString.equals("?")) {
-                url += url.contains("?") ? "&" : "?";
-                url += paramString;
-            }
-        }
-
-        return url;
-    }
-
-    /**
-     * Checks the InputStream if it contains  GZIP compressed data
-     *
-     * @param inputStream InputStream to be checked
-     * @return true or false if the stream contains GZIP compressed data
-     * @throws java.io.IOException if read from inputStream fails
-     */
-    public static boolean isInputStreamGZIPCompressed(final PushbackInputStream inputStream) throws IOException {
-        if (inputStream == null)
-            return false;
-
-        byte[] signature = new byte[2];
-        int readStatus = inputStream.read(signature);
-        inputStream.unread(signature);
-        int streamHeader = ((int) signature[0] & 0xff) | ((signature[1] << 8) & 0xff00);
-        return readStatus == 2 && GZIPInputStream.GZIP_MAGIC == streamHeader;
-    }
-
-    /**
-     * A utility function to close an input stream without raising an exception.
-     *
-     * @param is input stream to close safely
-     */
-    public static void silentCloseInputStream(InputStream is) {
-        try {
-            if (is != null) {
-                is.close();
-            }
-        } catch (IOException e) {
-            log.w(LOG_TAG, "Cannot close input stream", e);
-        }
-    }
-
-    /**
-     * A utility function to close an output stream without raising an exception.
-     *
-     * @param os output stream to close safely
-     */
-    public static void silentCloseOutputStream(OutputStream os) {
-        try {
-            if (os != null) {
-                os.close();
-            }
-        } catch (IOException e) {
-            log.w(LOG_TAG, "Cannot close output stream", e);
-        }
-    }
-
     /**
      * Returns HttpEntity containing data from RequestParams included with request declaration.
      * Allows also passing progress from upload via provided ResponseHandler
@@ -1561,48 +1587,17 @@ private HttpEntityEnclosingRequestBase addEntityToRequestBase(HttpEntityEnclosin
         return requestBase;
     }
 
-    /**
-     * This horrible hack is required on Android, due to implementation of BasicManagedEntity, which
-     * doesn't chain call consumeContent on underlying wrapped HttpEntity
-     *
-     * @param entity HttpEntity, may be null
-     */
-    public static void endEntityViaReflection(HttpEntity entity) {
-        if (entity instanceof HttpEntityWrapper) {
-            try {
-                Field f = null;
-                Field[] fields = HttpEntityWrapper.class.getDeclaredFields();
-                for (Field ff : fields) {
-                    if (ff.getName().equals("wrappedEntity")) {
-                        f = ff;
-                        break;
-                    }
-                }
-                if (f != null) {
-                    f.setAccessible(true);
-                    HttpEntity wrapped = (HttpEntity) f.get(entity);
-                    if (wrapped != null) {
-                        wrapped.consumeContent();
-                    }
-                }
-            } catch (Throwable t) {
-                log.e(LOG_TAG, "wrappedEntity consume", t);
-            }
-        }
-    }
-
     /**
      * Enclosing entity to hold stream of gzip decoded data for accessing HttpEntity contents
      */
     private static class InflatingEntity extends HttpEntityWrapper {
 
-        public InflatingEntity(HttpEntity wrapped) {
-            super(wrapped);
-        }
-
         InputStream wrappedStream;
         PushbackInputStream pushbackStream;
         GZIPInputStream gzippedStream;
+        public InflatingEntity(HttpEntity wrapped) {
+            super(wrapped);
+        }
 
         @Override
         public InputStream getContent() throws IOException {
diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java
index f8a49d5c1..1d92c9e2d 100755
--- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java
+++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java
@@ -18,17 +18,17 @@
 
 package com.loopj.android.http;
 
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpRequestRetryHandler;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.impl.client.AbstractHttpClient;
-import org.apache.http.protocol.HttpContext;
-
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.UnknownHostException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import cz.msebera.android.httpclient.HttpResponse;
+import cz.msebera.android.httpclient.client.HttpRequestRetryHandler;
+import cz.msebera.android.httpclient.client.methods.HttpUriRequest;
+import cz.msebera.android.httpclient.impl.client.AbstractHttpClient;
+import cz.msebera.android.httpclient.protocol.HttpContext;
+
 /**
  * Internal class, representing the HttpRequest, done in asynchronous manner
  */
@@ -37,8 +37,8 @@ public class AsyncHttpRequest implements Runnable {
     private final HttpContext context;
     private final HttpUriRequest request;
     private final ResponseHandlerInterface responseHandler;
-    private int executionCount;
     private final AtomicBoolean isCancelled = new AtomicBoolean();
+    private int executionCount;
     private boolean cancelIsNotified;
     private volatile boolean isFinished;
     private boolean isRequestPreProcessed;
diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java
index 5aa3524f0..609cc21a7 100755
--- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java
@@ -22,23 +22,23 @@
 import android.os.Looper;
 import android.os.Message;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.HttpResponseException;
-import org.apache.http.util.ByteArrayBuffer;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.net.URI;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+import cz.msebera.android.httpclient.HttpResponse;
+import cz.msebera.android.httpclient.StatusLine;
+import cz.msebera.android.httpclient.client.HttpResponseException;
+import cz.msebera.android.httpclient.util.ByteArrayBuffer;
+
 /**
  * Used to intercept and handle the responses from requests made using {@link AsyncHttpClient}. The
- * {@link #onSuccess(int, org.apache.http.Header[], byte[])} method is designed to be anonymously
+ * {@link #onSuccess(int, cz.msebera.android.httpclient.Header[], byte[])} method is designed to be anonymously
  * overridden with your own response handling code. 

 

Additionally, you can override the - * {@link #onFailure(int, org.apache.http.Header[], byte[], Throwable)}, {@link #onStart()}, {@link + * {@link #onFailure(int, cz.msebera.android.httpclient.Header[], byte[], Throwable)}, {@link #onStart()}, {@link * #onFinish()}, {@link #onRetry(int)} and {@link #onProgress(long, long)} methods as required. *

 

For example:

 

*
@@ -81,8 +81,8 @@
 @SuppressWarnings("ALL")
 public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterface {
 
-    private static final String LOG_TAG = "AsyncHttpRH";
-
+    public static final String DEFAULT_CHARSET = "UTF-8";
+    public static final String UTF8_BOM = "\uFEFF";
     protected static final int SUCCESS_MESSAGE = 0;
     protected static final int FAILURE_MESSAGE = 1;
     protected static final int START_MESSAGE = 2;
@@ -90,11 +90,8 @@ public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterfa
     protected static final int PROGRESS_MESSAGE = 4;
     protected static final int RETRY_MESSAGE = 5;
     protected static final int CANCEL_MESSAGE = 6;
-
     protected static final int BUFFER_SIZE = 4096;
-
-    public static final String DEFAULT_CHARSET = "UTF-8";
-    public static final String UTF8_BOM = "\uFEFF";
+    private static final String LOG_TAG = "AsyncHttpRH";
     private String responseCharset = DEFAULT_CHARSET;
     private Handler handler;
     private boolean useSynchronousMode;
@@ -150,13 +147,13 @@ public AsyncHttpResponseHandler(boolean usePoolThread) {
     }
 
     @Override
-    public void setTag(Object TAG) {
-        this.TAG = new WeakReference(TAG);
+    public Object getTag() {
+        return this.TAG.get();
     }
 
     @Override
-    public Object getTag() {
-        return this.TAG.get();
+    public void setTag(Object TAG) {
+        this.TAG = new WeakReference(TAG);
     }
 
     @Override
@@ -165,13 +162,13 @@ public URI getRequestURI() {
     }
 
     @Override
-    public Header[] getRequestHeaders() {
-        return this.requestHeaders;
+    public void setRequestURI(URI requestURI) {
+        this.requestURI = requestURI;
     }
 
     @Override
-    public void setRequestURI(URI requestURI) {
-        this.requestURI = requestURI;
+    public Header[] getRequestHeaders() {
+        return this.requestHeaders;
     }
 
     @Override
@@ -179,23 +176,6 @@ public void setRequestHeaders(Header[] requestHeaders) {
         this.requestHeaders = requestHeaders;
     }
 
-    /**
-     * Avoid leaks by using a non-anonymous handler class.
-     */
-    private static class ResponderHandler extends Handler {
-        private final AsyncHttpResponseHandler mResponder;
-
-        ResponderHandler(AsyncHttpResponseHandler mResponder, Looper looper) {
-            super(looper);
-            this.mResponder = mResponder;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            mResponder.handleMessage(msg);
-        }
-    }
-
     @Override
     public boolean getUseSynchronousMode() {
         return useSynchronousMode;
@@ -238,6 +218,10 @@ public void setUsePoolThread(boolean pool) {
         usePoolThread = pool;
     }
 
+    public String getCharset() {
+        return this.responseCharset == null ? DEFAULT_CHARSET : this.responseCharset;
+    }
+
     /**
      * Sets the charset for the response string. If not set, the default is UTF-8.
      *
@@ -248,10 +232,6 @@ public void setCharset(final String charset) {
         this.responseCharset = charset;
     }
 
-    public String getCharset() {
-        return this.responseCharset == null ? DEFAULT_CHARSET : this.responseCharset;
-    }
-
     /**
      * Fired when the request progress, override to handle in your own code
      *
@@ -513,4 +493,21 @@ byte[] getResponseData(HttpEntity entity) throws IOException {
         }
         return responseBody;
     }
+
+    /**
+     * Avoid leaks by using a non-anonymous handler class.
+     */
+    private static class ResponderHandler extends Handler {
+        private final AsyncHttpResponseHandler mResponder;
+
+        ResponderHandler(AsyncHttpResponseHandler mResponder, Looper looper) {
+            super(looper);
+            this.mResponder = mResponder;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            mResponder.handleMessage(msg);
+        }
+    }
 }
diff --git a/library/src/main/java/com/loopj/android/http/Base64.java b/library/src/main/java/com/loopj/android/http/Base64.java
index d994700fe..045b46ead 100755
--- a/library/src/main/java/com/loopj/android/http/Base64.java
+++ b/library/src/main/java/com/loopj/android/http/Base64.java
@@ -61,28 +61,8 @@ public class Base64 {
     //  shared code
     //  --------------------------------------------------------
 
-    /* package */ static abstract class Coder {
-        public byte[] output;
-        public int op;
-
-        /**
-         * Encode/decode another block of input data.  this.output is provided by the caller, and
-         * must be big enough to hold all the coded data.  On exit, this.opwill be set to the length
-         * of the coded data.
-         *
-         * @param finish true if this is the final call to process for this object.  Will finalize
-         *               the coder state and include any final bytes in the output.
-         * @return true if the input so far is good; false if some error has been detected in the
-         * input stream..
-         */
-        public abstract boolean process(byte[] input, int offset, int len, boolean finish);
-
-        /**
-         * @return the maximum number of bytes a call to process() could produce for the given
-         * number of input bytes.  This may be an overestimate.
-         */
-        public abstract int maxOutputSize(int len);
-    }
+    private Base64() {
+    }   // don't instantiate
 
     //  --------------------------------------------------------
     //  decoding
@@ -153,6 +133,131 @@ public static byte[] decode(byte[] input, int offset, int len, int flags) {
         return temp;
     }
 
+    /**
+     * Base64-encode the given data and return a newly allocated String with the result.
+     *
+     * @param input the data to encode
+     * @param flags controls certain features of the encoded output. Passing {@code DEFAULT} results
+     *              in output that adheres to RFC 2045.
+     * @return base64 string containing encoded input
+     */
+    public static String encodeToString(byte[] input, int flags) {
+        try {
+            return new String(encode(input, flags), "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            // US-ASCII is guaranteed to be available.
+            throw new AssertionError(e);
+        }
+    }
+
+    //  --------------------------------------------------------
+    //  encoding
+    //  --------------------------------------------------------
+
+    /**
+     * Base64-encode the given data and return a newly allocated String with the result.
+     *
+     * @param input  the data to encode
+     * @param offset the position within the input array at which to start
+     * @param len    the number of bytes of input to encode
+     * @param flags  controls certain features of the encoded output. Passing {@code DEFAULT}
+     *               results in output that adheres to RFC 2045.
+     * @return base64 string containing encoded range of input
+     */
+    public static String encodeToString(byte[] input, int offset, int len, int flags) {
+        try {
+            return new String(encode(input, offset, len, flags), "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            // US-ASCII is guaranteed to be available.
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Base64-encode the given data and return a newly allocated byte[] with the result.
+     *
+     * @param input the data to encode
+     * @param flags controls certain features of the encoded output. Passing {@code DEFAULT} results
+     *              in output that adheres to RFC 2045.
+     * @return base64 encoded input as bytes
+     */
+    public static byte[] encode(byte[] input, int flags) {
+        return encode(input, 0, input.length, flags);
+    }
+
+    /**
+     * Base64-encode the given data and return a newly allocated byte[] with the result.
+     *
+     * @param input  the data to encode
+     * @param offset the position within the input array at which to start
+     * @param len    the number of bytes of input to encode
+     * @param flags  controls certain features of the encoded output. Passing {@code DEFAULT}
+     *               results in output that adheres to RFC 2045.
+     * @return base64 encoded input as bytes
+     */
+    public static byte[] encode(byte[] input, int offset, int len, int flags) {
+        Encoder encoder = new Encoder(flags, null);
+
+        // Compute the exact length of the array we will produce.
+        int output_len = len / 3 * 4;
+
+        // Account for the tail of the data and the padding bytes, if any.
+        if (encoder.do_padding) {
+            if (len % 3 > 0) {
+                output_len += 4;
+            }
+        } else {
+            switch (len % 3) {
+                case 0:
+                    break;
+                case 1:
+                    output_len += 2;
+                    break;
+                case 2:
+                    output_len += 3;
+                    break;
+            }
+        }
+
+        // Account for the newlines, if any.
+        if (encoder.do_newline && len > 0) {
+            output_len += (((len - 1) / (3 * Encoder.LINE_GROUPS)) + 1) *
+                    (encoder.do_cr ? 2 : 1);
+        }
+
+        encoder.output = new byte[output_len];
+        encoder.process(input, offset, len, true);
+
+        if (BuildConfig.DEBUG && encoder.op != output_len) {
+            throw new AssertionError();
+        }
+
+        return encoder.output;
+    }
+
+    /* package */ static abstract class Coder {
+        public byte[] output;
+        public int op;
+
+        /**
+         * Encode/decode another block of input data.  this.output is provided by the caller, and
+         * must be big enough to hold all the coded data.  On exit, this.opwill be set to the length
+         * of the coded data.
+         *
+         * @param finish true if this is the final call to process for this object.  Will finalize
+         *               the coder state and include any final bytes in the output.
+         * @return true if the input so far is good; false if some error has been detected in the
+         * input stream..
+         */
+        public abstract boolean process(byte[] input, int offset, int len, boolean finish);
+
+        /**
+         * @return the maximum number of bytes a call to process() could produce for the given
+         * number of input bytes.  This may be an overestimate.
+         */
+        public abstract int maxOutputSize(int len);
+    }
+
     /* package */ static class Decoder extends Coder {
         /**
          * Lookup table for turning bytes into their position in the Base64 alphabet.
@@ -204,7 +309,7 @@ public static byte[] decode(byte[] input, int offset, int len, int flags) {
          */
         private static final int SKIP = -1;
         private static final int EQUALS = -2;
-
+        final private int[] alphabet;
         /**
          * States 0-3 are reading through the next input tuple. State 4 is having read one '=' and
          * expecting exactly one more. State 5 is expecting no more data or padding characters in
@@ -214,8 +319,6 @@ public static byte[] decode(byte[] input, int offset, int len, int flags) {
         private int state;   // state number (0 to 6)
         private int value;
 
-        final private int[] alphabet;
-
         public Decoder(int flags, byte[] output) {
             this.output = output;
 
@@ -415,108 +518,6 @@ public boolean process(byte[] input, int offset, int len, boolean finish) {
         }
     }
 
-    //  --------------------------------------------------------
-    //  encoding
-    //  --------------------------------------------------------
-
-    /**
-     * Base64-encode the given data and return a newly allocated String with the result.
-     *
-     * @param input the data to encode
-     * @param flags controls certain features of the encoded output. Passing {@code DEFAULT} results
-     *              in output that adheres to RFC 2045.
-     * @return base64 string containing encoded input
-     */
-    public static String encodeToString(byte[] input, int flags) {
-        try {
-            return new String(encode(input, flags), "US-ASCII");
-        } catch (UnsupportedEncodingException e) {
-            // US-ASCII is guaranteed to be available.
-            throw new AssertionError(e);
-        }
-    }
-
-    /**
-     * Base64-encode the given data and return a newly allocated String with the result.
-     *
-     * @param input  the data to encode
-     * @param offset the position within the input array at which to start
-     * @param len    the number of bytes of input to encode
-     * @param flags  controls certain features of the encoded output. Passing {@code DEFAULT}
-     *               results in output that adheres to RFC 2045.
-     * @return base64 string containing encoded range of input
-     */
-    public static String encodeToString(byte[] input, int offset, int len, int flags) {
-        try {
-            return new String(encode(input, offset, len, flags), "US-ASCII");
-        } catch (UnsupportedEncodingException e) {
-            // US-ASCII is guaranteed to be available.
-            throw new AssertionError(e);
-        }
-    }
-
-    /**
-     * Base64-encode the given data and return a newly allocated byte[] with the result.
-     *
-     * @param input the data to encode
-     * @param flags controls certain features of the encoded output. Passing {@code DEFAULT} results
-     *              in output that adheres to RFC 2045.
-     * @return base64 encoded input as bytes
-     */
-    public static byte[] encode(byte[] input, int flags) {
-        return encode(input, 0, input.length, flags);
-    }
-
-    /**
-     * Base64-encode the given data and return a newly allocated byte[] with the result.
-     *
-     * @param input  the data to encode
-     * @param offset the position within the input array at which to start
-     * @param len    the number of bytes of input to encode
-     * @param flags  controls certain features of the encoded output. Passing {@code DEFAULT}
-     *               results in output that adheres to RFC 2045.
-     * @return base64 encoded input as bytes
-     */
-    public static byte[] encode(byte[] input, int offset, int len, int flags) {
-        Encoder encoder = new Encoder(flags, null);
-
-        // Compute the exact length of the array we will produce.
-        int output_len = len / 3 * 4;
-
-        // Account for the tail of the data and the padding bytes, if any.
-        if (encoder.do_padding) {
-            if (len % 3 > 0) {
-                output_len += 4;
-            }
-        } else {
-            switch (len % 3) {
-                case 0:
-                    break;
-                case 1:
-                    output_len += 2;
-                    break;
-                case 2:
-                    output_len += 3;
-                    break;
-            }
-        }
-
-        // Account for the newlines, if any.
-        if (encoder.do_newline && len > 0) {
-            output_len += (((len - 1) / (3 * Encoder.LINE_GROUPS)) + 1) *
-                    (encoder.do_cr ? 2 : 1);
-        }
-
-        encoder.output = new byte[output_len];
-        encoder.process(input, offset, len, true);
-
-        if (BuildConfig.DEBUG && encoder.op != output_len) {
-            throw new AssertionError();
-        }
-
-        return encoder.output;
-    }
-
     /* package */ static class Encoder extends Coder {
         /**
          * Emit a new line every this many output tuples.  Corresponds to a 76-character line length
@@ -544,15 +545,13 @@ public static byte[] encode(byte[] input, int offset, int len, int flags) {
                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
         };
-
-        final private byte[] tail;
-        /* package */ int tailLen;
-        private int count;
-
         final public boolean do_padding;
         final public boolean do_newline;
         final public boolean do_cr;
+        final private byte[] tail;
         final private byte[] alphabet;
+        /* package */ int tailLen;
+        private int count;
 
         public Encoder(int flags, byte[] output) {
             this.output = output;
@@ -712,7 +711,4 @@ public boolean process(byte[] input, int offset, int len, boolean finish) {
             return true;
         }
     }
-
-    private Base64() {
-    }   // don't instantiate
 }
diff --git a/library/src/main/java/com/loopj/android/http/Base64OutputStream.java b/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
index af72f373a..07fb6f7cd 100755
--- a/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
+++ b/library/src/main/java/com/loopj/android/http/Base64OutputStream.java
@@ -21,14 +21,12 @@
 import java.io.OutputStream;
 
 public class Base64OutputStream extends FilterOutputStream {
+    private static final byte[] EMPTY = new byte[0];
     private final Base64.Coder coder;
     private final int flags;
-
     private byte[] buffer = null;
     private int bpos = 0;
 
-    private static final byte[] EMPTY = new byte[0];
-
     /**
      * Performs Base64 encoding on the data written to the stream, writing the encoded data to
      * another OutputStream.
diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java
index 02d7ec9b2..f9d5f9182 100755
--- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java
+++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java
@@ -18,14 +18,14 @@
 
 package com.loopj.android.http;
 
-import org.apache.http.Header;
-import org.apache.http.HttpStatus;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpStatus;
 
 /**
  * Class meant to be used with custom JSON parser (such as GSON or Jackson JSON) 

 

* {@link #parseResponse(String, boolean)} should be overriden and must return type of generic param * class, response will be then handled to implementation of abstract methods {@link #onSuccess(int, - * org.apache.http.Header[], String, Object)} or {@link #onFailure(int, org.apache.http.Header[], + * cz.msebera.android.httpclient.Header[], String, Object)} or {@link #onFailure(int, cz.msebera.android.httpclient.Header[], * Throwable, String, Object)}, depending of response HTTP status line (result http code) * * @param Generic type meant to be returned in callback diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index a891af560..865fd5efe 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -20,15 +20,15 @@ import android.os.Looper; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpResponseException; - import java.io.IOException; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpResponse; +import cz.msebera.android.httpclient.StatusLine; +import cz.msebera.android.httpclient.client.HttpResponseException; + /** * Used to intercept and handle the responses from requests made using {@link AsyncHttpClient}. * Receives response body as byte array with a content-type whitelist. (e.g. checks Content-Type @@ -60,16 +60,6 @@ public abstract class BinaryHttpResponseHandler extends AsyncHttpResponseHandler "image/gif" }; - /** - * Method can be overriden to return allowed content types, can be sometimes better than passing - * data in constructor - * - * @return array of content-types or Pattern string templates (eg. '.*' to match every response) - */ - public String[] getAllowedContentTypes() { - return mAllowedContentTypes; - } - /** * Creates a new BinaryHttpResponseHandler */ @@ -91,13 +81,13 @@ public BinaryHttpResponseHandler(String[] allowedContentTypes) { AsyncHttpClient.log.e(LOG_TAG, "Constructor passed allowedContentTypes was null !"); } } - + /** * Creates a new BinaryHttpResponseHandler with a user-supplied looper, and overrides the default allowed content types with * passed String array (hopefully) of content types. * * @param allowedContentTypes content types array, eg. 'image/jpeg' or pattern '.*' - * @param looper The looper to work with + * @param looper The looper to work with */ public BinaryHttpResponseHandler(String[] allowedContentTypes, Looper looper) { super(looper); @@ -108,6 +98,16 @@ public BinaryHttpResponseHandler(String[] allowedContentTypes, Looper looper) { } } + /** + * Method can be overriden to return allowed content types, can be sometimes better than passing + * data in constructor + * + * @return array of content-types or Pattern string templates (eg. '.*' to match every response) + */ + public String[] getAllowedContentTypes() { + return mAllowedContentTypes; + } + @Override public abstract void onSuccess(int statusCode, Header[] headers, byte[] binaryData); @@ -121,13 +121,13 @@ public final void sendResponseMessage(HttpResponse response) throws IOException if (contentTypeHeaders.length != 1) { //malformed/ambiguous HTTP Header, ABORT! sendFailureMessage( - status.getStatusCode(), - response.getAllHeaders(), - null, - new HttpResponseException( status.getStatusCode(), - "None, or more than one, Content-Type Header found!" - ) + response.getAllHeaders(), + null, + new HttpResponseException( + status.getStatusCode(), + "None, or more than one, Content-Type Header found!" + ) ); return; } @@ -145,13 +145,13 @@ public final void sendResponseMessage(HttpResponse response) throws IOException if (!foundAllowedContentType) { //Content-Type not in allowed list, ABORT! sendFailureMessage( - status.getStatusCode(), - response.getAllHeaders(), - null, - new HttpResponseException( status.getStatusCode(), - "Content-Type (" + contentTypeHeader.getValue() + ") not allowed!" - ) + response.getAllHeaders(), + null, + new HttpResponseException( + status.getStatusCode(), + "Content-Type (" + contentTypeHeader.getValue() + ") not allowed!" + ) ); return; } diff --git a/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java index 8ff6bcddd..a3e7b914e 100644 --- a/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BlackholeHttpResponseHandler.java @@ -1,7 +1,7 @@ package com.loopj.android.http; -import org.apache.http.Header; -import org.apache.http.HttpResponse; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpResponse; /** * Blank implementation of ResponseHandlerInterface, which ignores all contents returned by diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index 1d3ade69e..bd5218668 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -20,17 +20,16 @@ import android.os.Message; -import org.apache.http.HttpEntity; -import org.apache.http.util.ByteArrayBuffer; - import java.io.IOException; import java.io.InputStream; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.util.ByteArrayBuffer; + @SuppressWarnings("ALL") public abstract class DataAsyncHttpResponseHandler extends AsyncHttpResponseHandler { - private static final String LOG_TAG = "DataAsyncHttpRH"; - protected static final int PROGRESS_DATA_MESSAGE = 7; + private static final String LOG_TAG = "DataAsyncHttpRH"; /** * Creates a new AsyncHttpResponseHandler @@ -39,6 +38,36 @@ public DataAsyncHttpResponseHandler() { super(); } + /** + * Copies elements from {@code original} into a new array, from indexes start (inclusive) to end + * (exclusive). The original order of elements is preserved. If {@code end} is greater than + * {@code original.length}, the result is padded with the value {@code (byte) 0}. + * + * @param original the original array + * @param start the start index, inclusive + * @param end the end index, exclusive + * @return the new array + * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length} + * @throws IllegalArgumentException if {@code start > end} + * @throws NullPointerException if {@code original == null} + * @see java.util.Arrays + * @since 1.6 + */ + public static byte[] copyOfRange(byte[] original, int start, int end) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, NullPointerException { + if (start > end) { + throw new IllegalArgumentException(); + } + int originalLength = original.length; + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + int resultLength = end - start; + int copyLength = Math.min(resultLength, originalLength - start); + byte[] result = new byte[resultLength]; + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + /** * Fired when the request progress, override to handle in your own code * @@ -48,7 +77,6 @@ public void onProgressData(byte[] responseBody) { AsyncHttpClient.log.d(LOG_TAG, "onProgressData(byte[]) was not overriden, but callback was received"); } - final public void sendProgressDataMessage(byte[] responseBytes) { sendMessage(obtainMessage(PROGRESS_DATA_MESSAGE, new Object[]{responseBytes})); } @@ -119,35 +147,5 @@ byte[] getResponseData(HttpEntity entity) throws IOException { } return responseBody; } - - /** - * Copies elements from {@code original} into a new array, from indexes start (inclusive) to end - * (exclusive). The original order of elements is preserved. If {@code end} is greater than - * {@code original.length}, the result is padded with the value {@code (byte) 0}. - * - * @param original the original array - * @param start the start index, inclusive - * @param end the end index, exclusive - * @return the new array - * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length} - * @throws IllegalArgumentException if {@code start > end} - * @throws NullPointerException if {@code original == null} - * @see java.util.Arrays - * @since 1.6 - */ - public static byte[] copyOfRange(byte[] original, int start, int end) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, NullPointerException { - if (start > end) { - throw new IllegalArgumentException(); - } - int originalLength = original.length; - if (start < 0 || start > originalLength) { - throw new ArrayIndexOutOfBoundsException(); - } - int resultLength = end - start; - int copyLength = Math.min(resultLength, originalLength - start); - byte[] result = new byte[resultLength]; - System.arraycopy(original, start, result, 0, copyLength); - return result; - } } diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 0fc1bec46..da5addfcd 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -20,21 +20,21 @@ import android.content.Context; -import org.apache.http.Header; -import org.apache.http.HttpEntity; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; + public abstract class FileAsyncHttpResponseHandler extends AsyncHttpResponseHandler { + private static final String LOG_TAG = "FileAsyncHttpRH"; protected final File file; protected final boolean append; protected final boolean renameIfExists; protected File frontendFile; - private static final String LOG_TAG = "FileAsyncHttpRH"; /** * Obtains new FileAsyncHttpResponseHandler and stores response in passed file diff --git a/library/src/main/java/com/loopj/android/http/HttpDelete.java b/library/src/main/java/com/loopj/android/http/HttpDelete.java index 103a997be..29d74d65d 100644 --- a/library/src/main/java/com/loopj/android/http/HttpDelete.java +++ b/library/src/main/java/com/loopj/android/http/HttpDelete.java @@ -18,10 +18,10 @@ package com.loopj.android.http; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; - import java.net.URI; +import cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase; + /** * The current Android (API level 21) bundled version of the Apache Http Client does not implement * a HttpEntityEnclosingRequestBase type of HTTP DELETE method. diff --git a/library/src/main/java/com/loopj/android/http/HttpGet.java b/library/src/main/java/com/loopj/android/http/HttpGet.java index b5582737e..548a4ae77 100644 --- a/library/src/main/java/com/loopj/android/http/HttpGet.java +++ b/library/src/main/java/com/loopj/android/http/HttpGet.java @@ -18,10 +18,10 @@ package com.loopj.android.http; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; - import java.net.URI; +import cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase; + /** * The current Android (API level 21) bundled version of the Apache Http Client does not implement * a HttpEntityEnclosingRequestBase type of HTTP GET method. diff --git a/library/src/main/java/com/loopj/android/http/HttpPatch.java b/library/src/main/java/com/loopj/android/http/HttpPatch.java index 82e0c8714..31fd2cba3 100644 --- a/library/src/main/java/com/loopj/android/http/HttpPatch.java +++ b/library/src/main/java/com/loopj/android/http/HttpPatch.java @@ -18,10 +18,10 @@ package com.loopj.android.http; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; - import java.net.URI; +import cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase; + /** * The current Android (API level 21) bundled version of the Apache Http Client does not implement * the HTTP PATCH method. Until the Android version is updated this can serve in it's stead. diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index 5fa926912..b5bbe0a82 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -18,19 +18,20 @@ package com.loopj.android.http; -import org.apache.http.Header; -import org.apache.http.HttpStatus; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpStatus; + /** * Used to intercept and handle the responses from requests made using {@link AsyncHttpClient}, with * automatic parsing into a {@link JSONObject} or {@link JSONArray}.

 

This class is * designed to be passed to get, post, put and delete requests with the {@link #onSuccess(int, - * org.apache.http.Header[], org.json.JSONArray)} or {@link #onSuccess(int, - * org.apache.http.Header[], org.json.JSONObject)} methods anonymously overridden.

 

+ * cz.msebera.android.httpclient.Header[], org.json.JSONArray)} or {@link #onSuccess(int, + * cz.msebera.android.httpclient.Header[], org.json.JSONObject)} methods anonymously overridden.

 

* Additionally, you can override the other event methods from the parent class. */ public class JsonHttpResponseHandler extends TextHttpResponseHandler { diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index d191ab1e8..56514bc7b 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -20,10 +20,6 @@ import android.text.TextUtils; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.message.BasicHeader; - import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -34,6 +30,10 @@ import java.util.Set; import java.util.zip.GZIPOutputStream; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.message.BasicHeader; + /** * HTTP entity to upload JSON data using streams. This has very low memory footprint; suitable for * uploading large files using base64 encoding. @@ -47,27 +47,22 @@ public class JsonStreamerEntity implements HttpEntity { // Size of the byte-array buffer used in I/O streams. private static final int BUFFER_SIZE = 4096; - - // Buffer used for reading from input streams. - private final byte[] buffer = new byte[BUFFER_SIZE]; - private static final byte[] JSON_TRUE = "true".getBytes(); private static final byte[] JSON_FALSE = "false".getBytes(); private static final byte[] JSON_NULL = "null".getBytes(); private static final byte[] STREAM_NAME = escape("name"); private static final byte[] STREAM_TYPE = escape("type"); private static final byte[] STREAM_CONTENTS = escape("contents"); - private static final Header HEADER_JSON_CONTENT = new BasicHeader( AsyncHttpClient.HEADER_CONTENT_TYPE, RequestParams.APPLICATION_JSON); - private static final Header HEADER_GZIP_ENCODING = new BasicHeader( AsyncHttpClient.HEADER_CONTENT_ENCODING, AsyncHttpClient.ENCODING_GZIP); - + // Buffer used for reading from input streams. + private final byte[] buffer = new byte[BUFFER_SIZE]; // JSON data and associated meta-data to be uploaded. private final Map jsonParams = new HashMap(); @@ -86,6 +81,68 @@ public JsonStreamerEntity(ResponseHandlerInterface progressHandler, boolean useG : escape(elapsedField); } + // Curtosy of Simple-JSON: https://goo.gl/XoW8RF + // Changed a bit to suit our needs in this class. + static byte[] escape(String string) { + // If it's null, just return prematurely. + if (string == null) { + return JSON_NULL; + } + + // Create a string builder to generate the escaped string. + StringBuilder sb = new StringBuilder(128); + + // Surround with quotations. + sb.append('"'); + + int length = string.length(), pos = -1; + while (++pos < length) { + char ch = string.charAt(pos); + switch (ch) { + case '"': + sb.append("\\\""); + break; + case '\\': + sb.append("\\\\"); + break; + case '\b': + sb.append("\\b"); + break; + case '\f': + sb.append("\\f"); + break; + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\t': + sb.append("\\t"); + break; + default: + // Reference: https://www.unicode.org/versions/Unicode5.1.0/ + if ((ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) { + String intString = Integer.toHexString(ch); + sb.append("\\u"); + int intLength = 4 - intString.length(); + for (int zero = 0; zero < intLength; zero++) { + sb.append('0'); + } + sb.append(intString.toUpperCase(Locale.US)); + } else { + sb.append(ch); + } + break; + } + } + + // Surround with quotations. + sb.append('"'); + + return sb.toString().getBytes(); + } + /** * Add content parameter, identified by the given key, to the request. * @@ -331,66 +388,4 @@ private void writeMetaData(OutputStream os, String name, String contentType) thr private void endMetaData(OutputStream os) throws IOException { os.write('"'); } - - // Curtosy of Simple-JSON: https://goo.gl/XoW8RF - // Changed a bit to suit our needs in this class. - static byte[] escape(String string) { - // If it's null, just return prematurely. - if (string == null) { - return JSON_NULL; - } - - // Create a string builder to generate the escaped string. - StringBuilder sb = new StringBuilder(128); - - // Surround with quotations. - sb.append('"'); - - int length = string.length(), pos = -1; - while (++pos < length) { - char ch = string.charAt(pos); - switch (ch) { - case '"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - case '\b': - sb.append("\\b"); - break; - case '\f': - sb.append("\\f"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\t': - sb.append("\\t"); - break; - default: - // Reference: https://www.unicode.org/versions/Unicode5.1.0/ - if ((ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) { - String intString = Integer.toHexString(ch); - sb.append("\\u"); - int intLength = 4 - intString.length(); - for (int zero = 0; zero < intLength; zero++) { - sb.append('0'); - } - sb.append(intString.toUpperCase(Locale.US)); - } else { - sb.append(ch); - } - break; - } - } - - // Surround with quotations. - sb.append('"'); - - return sb.toString().getBytes(); - } } diff --git a/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java b/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java index 80a5eb614..5ee6f6d0f 100644 --- a/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java +++ b/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java @@ -18,24 +18,24 @@ package com.loopj.android.http; -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.ProtocolException; -import org.apache.http.client.CircularRedirectException; -import org.apache.http.client.params.ClientPNames; -import org.apache.http.client.utils.URIUtils; -import org.apache.http.impl.client.DefaultRedirectHandler; -import org.apache.http.impl.client.RedirectLocations; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.ExecutionContext; -import org.apache.http.protocol.HttpContext; - import java.net.URI; import java.net.URISyntaxException; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpHost; +import cz.msebera.android.httpclient.HttpRequest; +import cz.msebera.android.httpclient.HttpResponse; +import cz.msebera.android.httpclient.HttpStatus; +import cz.msebera.android.httpclient.ProtocolException; +import cz.msebera.android.httpclient.client.CircularRedirectException; +import cz.msebera.android.httpclient.client.params.ClientPNames; +import cz.msebera.android.httpclient.client.utils.URIUtils; +import cz.msebera.android.httpclient.impl.client.DefaultRedirectHandler; +import cz.msebera.android.httpclient.impl.client.RedirectLocations; +import cz.msebera.android.httpclient.params.HttpParams; +import cz.msebera.android.httpclient.protocol.ExecutionContext; +import cz.msebera.android.httpclient.protocol.HttpContext; + /** * Taken from StackOverflow * diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 67d6becc8..6d88a68d3 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -18,19 +18,6 @@ package com.loopj.android.http; -import org.apache.http.HttpVersion; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.HTTP; - import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -50,6 +37,19 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import cz.msebera.android.httpclient.HttpVersion; +import cz.msebera.android.httpclient.conn.ClientConnectionManager; +import cz.msebera.android.httpclient.conn.scheme.PlainSocketFactory; +import cz.msebera.android.httpclient.conn.scheme.Scheme; +import cz.msebera.android.httpclient.conn.scheme.SchemeRegistry; +import cz.msebera.android.httpclient.conn.ssl.SSLSocketFactory; +import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; +import cz.msebera.android.httpclient.impl.conn.tsccm.ThreadSafeClientConnManager; +import cz.msebera.android.httpclient.params.BasicHttpParams; +import cz.msebera.android.httpclient.params.HttpParams; +import cz.msebera.android.httpclient.params.HttpProtocolParams; +import cz.msebera.android.httpclient.protocol.HTTP; + /** * This file is introduced to fix HTTPS Post bug on API < ICS see * https://code.google.com/p/android/issues/detail?id=13117#c14

 

Warning! This omits SSL @@ -85,23 +85,6 @@ public X509Certificate[] getAcceptedIssuers() { sslContext.init(null, new TrustManager[]{tm}, null); } - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - } - - @Override - public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); - } - - /** - * Makes HttpsURLConnection trusts a set of certificates specified by the KeyStore - */ - public void fixHttpsURLConnection() { - HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); - } - /** * Gets a KeyStore containing the Certificate * @@ -201,4 +184,21 @@ public static DefaultHttpClient getNewHttpClient(KeyStore keyStore) { } } + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket() throws IOException { + return sslContext.getSocketFactory().createSocket(); + } + + /** + * Makes HttpsURLConnection trusts a set of certificates specified by the KeyStore + */ + public void fixHttpsURLConnection() { + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + } + } diff --git a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java index 04708281b..b3419ea16 100755 --- a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java +++ b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java @@ -22,9 +22,6 @@ import android.content.SharedPreferences; import android.text.TextUtils; -import org.apache.http.client.CookieStore; -import org.apache.http.cookie.Cookie; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -36,6 +33,9 @@ import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; +import cz.msebera.android.httpclient.client.CookieStore; +import cz.msebera.android.httpclient.cookie.Cookie; + /** * A persistent cookie store which implements the Apache HttpClient {@link CookieStore} interface. * Cookies are stored and will persist on the user's device between application sessions since they @@ -48,10 +48,9 @@ public class PersistentCookieStore implements CookieStore { private static final String COOKIE_PREFS = "CookiePrefsFile"; private static final String COOKIE_NAME_STORE = "names"; private static final String COOKIE_NAME_PREFIX = "cookie_"; - private boolean omitNonPersistentCookies = false; - private final ConcurrentHashMap cookies; private final SharedPreferences cookiePrefs; + private boolean omitNonPersistentCookies = false; /** * Construct a persistent cookie store. diff --git a/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java index 06abdf0d1..09a265b69 100644 --- a/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java +++ b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java @@ -18,21 +18,21 @@ package com.loopj.android.http; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.AuthState; -import org.apache.http.auth.Credentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.protocol.ExecutionContext; -import org.apache.http.protocol.HttpContext; - import java.io.IOException; +import cz.msebera.android.httpclient.HttpException; +import cz.msebera.android.httpclient.HttpHost; +import cz.msebera.android.httpclient.HttpRequest; +import cz.msebera.android.httpclient.HttpRequestInterceptor; +import cz.msebera.android.httpclient.auth.AuthScope; +import cz.msebera.android.httpclient.auth.AuthState; +import cz.msebera.android.httpclient.auth.Credentials; +import cz.msebera.android.httpclient.client.CredentialsProvider; +import cz.msebera.android.httpclient.client.protocol.ClientContext; +import cz.msebera.android.httpclient.impl.auth.BasicScheme; +import cz.msebera.android.httpclient.protocol.ExecutionContext; +import cz.msebera.android.httpclient.protocol.HttpContext; + public class PreemptiveAuthorizationHttpRequestInterceptor implements HttpRequestInterceptor { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index ba8a666c5..2e6e8233d 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -18,19 +18,19 @@ package com.loopj.android.http; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpResponseException; -import org.apache.http.client.methods.HttpUriRequest; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.HttpResponse; +import cz.msebera.android.httpclient.HttpStatus; +import cz.msebera.android.httpclient.StatusLine; +import cz.msebera.android.httpclient.client.HttpResponseException; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; + public abstract class RangeFileAsyncHttpResponseHandler extends FileAsyncHttpResponseHandler { private static final String LOG_TAG = "RangeFileAsyncHttpRH"; diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index 3992185c7..6908ae93f 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -96,6 +96,16 @@ public boolean shouldBeGarbageCollected() { return should; } + /** + * Will return TAG of underlying AsyncHttpRequest if it's not already GCed + * + * @return Object TAG, can be null + */ + public Object getTag() { + AsyncHttpRequest _request = request.get(); + return _request == null ? null : _request.getTag(); + } + /** * Will set Object as TAG to underlying AsyncHttpRequest * @@ -108,14 +118,4 @@ public RequestHandle setTag(Object tag) { _request.setRequestTag(tag); return this; } - - /** - * Will return TAG of underlying AsyncHttpRequest if it's not already GCed - * - * @return Object TAG, can be null - */ - public Object getTag() { - AsyncHttpRequest _request = request.get(); - return _request == null ? null : _request.getTag(); - } } \ No newline at end of file diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 1536ab2d3..0387b9285 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -18,12 +18,6 @@ package com.loopj.android.http; -import org.apache.http.HttpEntity; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.protocol.HTTP; - import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -41,6 +35,12 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.client.entity.UrlEncodedFormEntity; +import cz.msebera.android.httpclient.client.utils.URLEncodedUtils; +import cz.msebera.android.httpclient.message.BasicNameValuePair; +import cz.msebera.android.httpclient.protocol.HTTP; + /** * A collection of string request parameters or files to send along with requests made from an * {@link AsyncHttpClient} instance.

 

For example:

 

@@ -99,44 +99,18 @@ public class RequestParams implements Serializable { "application/json"; protected final static String LOG_TAG = "RequestParams"; - protected boolean isRepeatable; - protected boolean forceMultipartEntity = false; - protected boolean useJsonStreamer; - protected String elapsedFieldInJsonStreamer = "_elapsed"; - protected boolean autoCloseInputStreams; protected final ConcurrentHashMap urlParams = new ConcurrentHashMap(); protected final ConcurrentHashMap streamParams = new ConcurrentHashMap(); protected final ConcurrentHashMap fileParams = new ConcurrentHashMap(); protected final ConcurrentHashMap> fileArrayParams = new ConcurrentHashMap>(); protected final ConcurrentHashMap urlParamsWithObjects = new ConcurrentHashMap(); + protected boolean isRepeatable; + protected boolean forceMultipartEntity = false; + protected boolean useJsonStreamer; + protected String elapsedFieldInJsonStreamer = "_elapsed"; + protected boolean autoCloseInputStreams; protected String contentEncoding = HTTP.UTF_8; - /** - * Sets content encoding for return value of {@link #getParamString()} and {@link - * #createFormEntity()}

 

Default encoding is "UTF-8" - * - * @param encoding String constant from {@link HTTP} - */ - public void setContentEncoding(final String encoding) { - if (encoding != null) { - this.contentEncoding = encoding; - } else { - AsyncHttpClient.log.d(LOG_TAG, "setContentEncoding called with null attribute"); - } - } - - /** - * If set to true will force Content-Type header to `multipart/form-data` - * even if there are not Files or Streams to be send - *

 

- * Default value is false - * - * @param force boolean, should declare content-type multipart/form-data even without files or streams present - */ - public void setForceMultipartEntityContentType(boolean force) { - this.forceMultipartEntity = force; - } - /** * Constructs a new empty {@code RequestParams} instance. */ @@ -190,6 +164,32 @@ public RequestParams(Object... keysAndValues) { } } + /** + * Sets content encoding for return value of {@link #getParamString()} and {@link + * #createFormEntity()}

 

Default encoding is "UTF-8" + * + * @param encoding String constant from {@link HTTP} + */ + public void setContentEncoding(final String encoding) { + if (encoding != null) { + this.contentEncoding = encoding; + } else { + AsyncHttpClient.log.d(LOG_TAG, "setContentEncoding called with null attribute"); + } + } + + /** + * If set to true will force Content-Type header to `multipart/form-data` + * even if there are not Files or Streams to be send + *

 

+ * Default value is false + * + * @param force boolean, should declare content-type multipart/form-data even without files or streams present + */ + public void setForceMultipartEntityContentType(boolean force) { + this.forceMultipartEntity = force; + } + /** * Adds a key/value string pair to the request. * @@ -510,7 +510,7 @@ public void setAutoCloseInputStreams(boolean flag) { * * @param progressHandler HttpResponseHandler for reporting progress on entity submit * @return HttpEntity resulting HttpEntity to be included along with {@link - * org.apache.http.client.methods.HttpEntityEnclosingRequestBase} + * cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase} * @throws IOException if one of the streams cannot be read */ public HttpEntity getEntity(ResponseHandlerInterface progressHandler) throws IOException { diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index 82fbc1bc5..c5936fb43 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -18,12 +18,12 @@ package com.loopj.android.http; -import org.apache.http.Header; -import org.apache.http.HttpResponse; - import java.io.IOException; import java.net.URI; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpResponse; + /** * Interface to standardize implementations */ @@ -93,13 +93,6 @@ public interface ResponseHandlerInterface { */ URI getRequestURI(); - /** - * Returns Header[] which were used to request - * - * @return headers from origin request - */ - Header[] getRequestHeaders(); - /** * Helper for handlers to receive Request URI info * @@ -108,18 +101,18 @@ public interface ResponseHandlerInterface { void setRequestURI(URI requestURI); /** - * Helper for handlers to receive Request Header[] info + * Returns Header[] which were used to request * - * @param requestHeaders Headers, claimed to be from original request + * @return headers from origin request */ - void setRequestHeaders(Header[] requestHeaders); + Header[] getRequestHeaders(); /** - * Can set, whether the handler should be asynchronous or synchronous + * Helper for handlers to receive Request Header[] info * - * @param useSynchronousMode whether data should be handled on background Thread on UI Thread + * @param requestHeaders Headers, claimed to be from original request */ - void setUseSynchronousMode(boolean useSynchronousMode); + void setRequestHeaders(Header[] requestHeaders); /** * Returns whether the handler is asynchronous or synchronous @@ -129,12 +122,11 @@ public interface ResponseHandlerInterface { boolean getUseSynchronousMode(); /** - * Sets whether the handler should be executed on the pool's thread or the - * UI thread + * Can set, whether the handler should be asynchronous or synchronous * - * @param usePoolThread if the ResponseHandler should run on pool's thread + * @param useSynchronousMode whether data should be handled on background Thread on UI Thread */ - void setUsePoolThread(boolean usePoolThread); + void setUseSynchronousMode(boolean useSynchronousMode); /** * Returns whether the handler should be executed on the pool's thread @@ -144,6 +136,14 @@ public interface ResponseHandlerInterface { */ boolean getUsePoolThread(); + /** + * Sets whether the handler should be executed on the pool's thread or the + * UI thread + * + * @param usePoolThread if the ResponseHandler should run on pool's thread + */ + void setUsePoolThread(boolean usePoolThread); + /** * This method is called once by the system when the response is about to be * processed by the system. The library makes sure that a single response @@ -173,17 +173,17 @@ public interface ResponseHandlerInterface { void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response); /** - * Will set TAG to ResponseHandlerInterface implementation, which can be then obtained - * in implemented methods, such as onSuccess, onFailure, ... + * Will retrieve TAG Object if it's not already freed from memory * - * @param TAG Object to be set as TAG, will be placed in WeakReference + * @return Object TAG or null if it's been garbage collected */ - void setTag(Object TAG); + Object getTag(); /** - * Will retrieve TAG Object if it's not already freed from memory + * Will set TAG to ResponseHandlerInterface implementation, which can be then obtained + * in implemented methods, such as onSuccess, onFailure, ... * - * @return Object TAG or null if it's been garbage collected + * @param TAG Object to be set as TAG, will be placed in WeakReference */ - Object getTag(); + void setTag(Object TAG); } diff --git a/library/src/main/java/com/loopj/android/http/RetryHandler.java b/library/src/main/java/com/loopj/android/http/RetryHandler.java index 7dba7a45f..6f519b9f4 100755 --- a/library/src/main/java/com/loopj/android/http/RetryHandler.java +++ b/library/src/main/java/com/loopj/android/http/RetryHandler.java @@ -25,12 +25,6 @@ import android.os.SystemClock; -import org.apache.http.NoHttpResponseException; -import org.apache.http.client.HttpRequestRetryHandler; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.protocol.ExecutionContext; -import org.apache.http.protocol.HttpContext; - import java.io.IOException; import java.io.InterruptedIOException; import java.net.SocketException; @@ -39,6 +33,12 @@ import javax.net.ssl.SSLException; +import cz.msebera.android.httpclient.NoHttpResponseException; +import cz.msebera.android.httpclient.client.HttpRequestRetryHandler; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; +import cz.msebera.android.httpclient.protocol.ExecutionContext; +import cz.msebera.android.httpclient.protocol.HttpContext; + class RetryHandler implements HttpRequestRetryHandler { private final static HashSet> exceptionWhitelist = new HashSet>(); private final static HashSet> exceptionBlacklist = new HashSet>(); @@ -65,6 +65,14 @@ public RetryHandler(int maxRetries, int retrySleepTimeMS) { this.retrySleepTimeMS = retrySleepTimeMS; } + static void addClassToWhitelist(Class cls) { + exceptionWhitelist.add(cls); + } + + static void addClassToBlacklist(Class cls) { + exceptionBlacklist.add(cls); + } + @Override public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { boolean retry = true; @@ -103,14 +111,6 @@ public boolean retryRequest(IOException exception, int executionCount, HttpConte return retry; } - static void addClassToWhitelist(Class cls) { - exceptionWhitelist.add(cls); - } - - static void addClassToBlacklist(Class cls) { - exceptionBlacklist.add(cls); - } - protected boolean isInList(HashSet> list, Throwable error) { for (Class aList : list) { if (aList.isInstance(error)) { diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index fd0a2b58d..c13428626 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -18,8 +18,6 @@ package com.loopj.android.http; -import org.apache.http.Header; -import org.apache.http.HttpEntity; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -33,6 +31,9 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; + /** * Provides interface to deserialize SAX responses, using AsyncHttpResponseHandler. Can be used like * this @@ -58,11 +59,11 @@ */ public abstract class SaxAsyncHttpResponseHandler extends AsyncHttpResponseHandler { + private final static String LOG_TAG = "SaxAsyncHttpRH"; /** * Generic Type of handler */ private T handler = null; - private final static String LOG_TAG = "SaxAsyncHttpRH"; /** * Constructs new SaxAsyncHttpResponseHandler with given handler instance @@ -84,7 +85,7 @@ public SaxAsyncHttpResponseHandler(T t) { * @param entity returned HttpEntity * @return deconstructed response * @throws java.io.IOException if there is problem assembling SAX response from stream - * @see org.apache.http.HttpEntity + * @see cz.msebera.android.httpclient.HttpEntity */ @Override protected byte[] getResponseData(HttpEntity entity) throws IOException { diff --git a/library/src/main/java/com/loopj/android/http/SerializableCookie.java b/library/src/main/java/com/loopj/android/http/SerializableCookie.java index ef8895eb7..1801b536e 100755 --- a/library/src/main/java/com/loopj/android/http/SerializableCookie.java +++ b/library/src/main/java/com/loopj/android/http/SerializableCookie.java @@ -18,15 +18,15 @@ package com.loopj.android.http; -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.cookie.BasicClientCookie; - import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; +import cz.msebera.android.httpclient.cookie.Cookie; +import cz.msebera.android.httpclient.impl.cookie.BasicClientCookie; + /** * A wrapper class around {@link Cookie} and/or {@link BasicClientCookie} designed for use in {@link * PersistentCookieStore}. diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index 541b3d5a7..a9c416793 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -25,11 +25,6 @@ import android.text.TextUtils; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.message.BasicHeader; -import org.apache.http.protocol.HTTP; - import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -40,6 +35,11 @@ import java.util.List; import java.util.Random; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.message.BasicHeader; +import cz.msebera.android.httpclient.protocol.HTTP; + /** * Simplified multipart entity mainly used for sending one or more files. */ @@ -58,16 +58,12 @@ class SimpleMultipartEntity implements HttpEntity { private final String boundary; private final byte[] boundaryLine; private final byte[] boundaryEnd; - private boolean isRepeatable; - private final List fileParts = new ArrayList(); - // The buffer we use for building the message excluding files and the last // boundary private final ByteArrayOutputStream out = new ByteArrayOutputStream(); - private final ResponseHandlerInterface progressHandler; - + private boolean isRepeatable; private long bytesWritten; private long totalSize; @@ -170,62 +166,6 @@ private void updateProgress(long count) { progressHandler.sendProgressMessage(bytesWritten, totalSize); } - private class FilePart { - public final File file; - public final byte[] header; - - public FilePart(String key, File file, String type, String customFileName) { - header = createHeader(key, TextUtils.isEmpty(customFileName) ? file.getName() : customFileName, type); - this.file = file; - } - - public FilePart(String key, File file, String type) { - header = createHeader(key, file.getName(), type); - this.file = file; - } - - private byte[] createHeader(String key, String filename, String type) { - ByteArrayOutputStream headerStream = new ByteArrayOutputStream(); - try { - headerStream.write(boundaryLine); - - // Headers - headerStream.write(createContentDisposition(key, filename)); - headerStream.write(createContentType(type)); - headerStream.write(TRANSFER_ENCODING_BINARY); - headerStream.write(CR_LF); - } catch (IOException e) { - // Can't happen on ByteArrayOutputStream - AsyncHttpClient.log.e(LOG_TAG, "createHeader ByteArrayOutputStream exception", e); - } - return headerStream.toByteArray(); - } - - public long getTotalLength() { - long streamLength = file.length() + CR_LF.length; - return header.length + streamLength; - } - - public void writeTo(OutputStream out) throws IOException { - out.write(header); - updateProgress(header.length); - - FileInputStream inputStream = new FileInputStream(file); - final byte[] tmp = new byte[4096]; - int bytesRead; - while ((bytesRead = inputStream.read(tmp)) != -1) { - out.write(tmp, 0, bytesRead); - updateProgress(bytesRead); - } - out.write(CR_LF); - updateProgress(CR_LF.length); - out.flush(); - AsyncHttpClient.silentCloseInputStream(inputStream); - } - } - - // The following methods are from the HttpEntity interface - @Override public long getContentLength() { long contentLen = out.size(); @@ -240,6 +180,8 @@ public long getContentLength() { return contentLen; } + // The following methods are from the HttpEntity interface + @Override public Header getContentType() { return new BasicHeader( @@ -298,4 +240,58 @@ public InputStream getContent() throws IOException, UnsupportedOperationExceptio throw new UnsupportedOperationException( "getContent() is not supported. Use writeTo() instead."); } + + private class FilePart { + public final File file; + public final byte[] header; + + public FilePart(String key, File file, String type, String customFileName) { + header = createHeader(key, TextUtils.isEmpty(customFileName) ? file.getName() : customFileName, type); + this.file = file; + } + + public FilePart(String key, File file, String type) { + header = createHeader(key, file.getName(), type); + this.file = file; + } + + private byte[] createHeader(String key, String filename, String type) { + ByteArrayOutputStream headerStream = new ByteArrayOutputStream(); + try { + headerStream.write(boundaryLine); + + // Headers + headerStream.write(createContentDisposition(key, filename)); + headerStream.write(createContentType(type)); + headerStream.write(TRANSFER_ENCODING_BINARY); + headerStream.write(CR_LF); + } catch (IOException e) { + // Can't happen on ByteArrayOutputStream + AsyncHttpClient.log.e(LOG_TAG, "createHeader ByteArrayOutputStream exception", e); + } + return headerStream.toByteArray(); + } + + public long getTotalLength() { + long streamLength = file.length() + CR_LF.length; + return header.length + streamLength; + } + + public void writeTo(OutputStream out) throws IOException { + out.write(header); + updateProgress(header.length); + + FileInputStream inputStream = new FileInputStream(file); + final byte[] tmp = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(tmp)) != -1) { + out.write(tmp, 0, bytesRead); + updateProgress(bytesRead); + } + out.write(CR_LF); + updateProgress(CR_LF.length); + out.flush(); + AsyncHttpClient.silentCloseInputStream(inputStream); + } + } } diff --git a/library/src/main/java/com/loopj/android/http/SyncHttpClient.java b/library/src/main/java/com/loopj/android/http/SyncHttpClient.java index 6d969134e..2d67f806e 100755 --- a/library/src/main/java/com/loopj/android/http/SyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/SyncHttpClient.java @@ -19,10 +19,10 @@ import android.content.Context; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.HttpContext; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; +import cz.msebera.android.httpclient.conn.scheme.SchemeRegistry; +import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; +import cz.msebera.android.httpclient.protocol.HttpContext; /** * Processes http requests in synchronous mode, so your caller thread will be blocked on each diff --git a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java index 709123ff1..c2ffc7fa9 100755 --- a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java @@ -18,15 +18,15 @@ package com.loopj.android.http; -import org.apache.http.Header; - import java.io.UnsupportedEncodingException; +import cz.msebera.android.httpclient.Header; + /** * Used to intercept and handle the responses from requests made using {@link AsyncHttpClient}. The - * {@link #onSuccess(int, org.apache.http.Header[], String)} method is designed to be anonymously + * {@link #onSuccess(int, cz.msebera.android.httpclient.Header[], String)} method is designed to be anonymously * overridden with your own response handling code.

 

Additionally, you can override the - * {@link #onFailure(int, org.apache.http.Header[], String, Throwable)}, {@link #onStart()}, and + * {@link #onFailure(int, cz.msebera.android.httpclient.Header[], String, Throwable)}, {@link #onStart()}, and * {@link #onFinish()} methods as required.

 

For example:

 

*
  * AsyncHttpClient client = new AsyncHttpClient();
@@ -74,6 +74,26 @@ public TextHttpResponseHandler(String encoding) {
         setCharset(encoding);
     }
 
+    /**
+     * Attempts to encode response bytes as string of set encoding
+     *
+     * @param charset     charset to create string with
+     * @param stringBytes response bytes
+     * @return String of set encoding or null
+     */
+    public static String getResponseString(byte[] stringBytes, String charset) {
+        try {
+            String toReturn = (stringBytes == null) ? null : new String(stringBytes, charset);
+            if (toReturn != null && toReturn.startsWith(UTF8_BOM)) {
+                return toReturn.substring(1);
+            }
+            return toReturn;
+        } catch (UnsupportedEncodingException e) {
+            AsyncHttpClient.log.e(LOG_TAG, "Encoding response into string failed", e);
+            return null;
+        }
+    }
+
     /**
      * Called when request fails
      *
@@ -102,24 +122,4 @@ public void onSuccess(int statusCode, Header[] headers, byte[] responseBytes) {
     public void onFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
         onFailure(statusCode, headers, getResponseString(responseBytes, getCharset()), throwable);
     }
-
-    /**
-     * Attempts to encode response bytes as string of set encoding
-     *
-     * @param charset     charset to create string with
-     * @param stringBytes response bytes
-     * @return String of set encoding or null
-     */
-    public static String getResponseString(byte[] stringBytes, String charset) {
-        try {
-            String toReturn = (stringBytes == null) ? null : new String(stringBytes, charset);
-            if (toReturn != null && toReturn.startsWith(UTF8_BOM)) {
-                return toReturn.substring(1);
-            }
-            return toReturn;
-        } catch (UnsupportedEncodingException e) {
-            AsyncHttpClient.log.e(LOG_TAG, "Encoding response into string failed", e);
-            return null;
-        }
-    }
 }
diff --git a/sample/build.gradle b/sample/build.gradle
index 749a8118d..eb44af0e7 100755
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -9,8 +9,7 @@ repositories {
 
 android {
     compileSdkVersion 23
-    buildToolsVersion '23.0.0'
-    useLibrary 'org.apache.http.legacy'
+    buildToolsVersion '23.0.1'
 
     defaultConfig {
         minSdkVersion 3
diff --git a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
index 9ba4d9dde..62589a3c0 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java
@@ -28,23 +28,22 @@
 import com.loopj.android.http.RequestHandle;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 public class AsyncBackgroundThreadSample extends SampleParentActivity {
     private static final String LOG_TAG = "AsyncBackgroundThreadSample";
 
     private final ExecutorService executor = Executors.newSingleThreadExecutor();
 
     @Override
-    public void onStop()
-    {
+    public void onStop() {
         super.onStop();
     }
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java b/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java
index 7123b7fe5..fea76991d 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java
@@ -23,8 +23,8 @@
 import com.loopj.android.http.RequestHandle;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
 
 public class BinarySample extends SampleParentActivity {
     private static final String LOG_TAG = "BinarySample";
diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java
index 25ee6bd0a..aab1ce744 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java
@@ -25,8 +25,8 @@
 import com.loopj.android.http.RequestHandle;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
 
 public class CancelRequestByTagSample extends ThreadingTimeoutSample {
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/ContentTypeForHttpEntitySample.java b/sample/src/main/java/com/loopj/android/http/sample/ContentTypeForHttpEntitySample.java
index 111b91be6..aa7183c6a 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/ContentTypeForHttpEntitySample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/ContentTypeForHttpEntitySample.java
@@ -8,12 +8,12 @@
 import com.loopj.android.http.ResponseHandlerInterface;
 import com.loopj.android.http.TextHttpResponseHandler;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-
 import java.io.File;
 import java.io.IOException;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 public class ContentTypeForHttpEntitySample extends SampleParentActivity {
     private static final String LOG_TAG = "ContentTypeForHttpEntitySample";
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java b/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java
index 83ef5c8f7..faf14ffc2 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java
@@ -23,9 +23,9 @@
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.util.Log;
+
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.databind.ObjectMapper;
-
 import com.loopj.android.http.AsyncHttpClient;
 import com.loopj.android.http.BaseJsonHttpResponseHandler;
 import com.loopj.android.http.RequestHandle;
@@ -33,9 +33,6 @@
 import com.loopj.android.http.sample.util.SampleJSON;
 import com.loopj.android.http.sample.util.SecureSocketFactory;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyManagementException;
@@ -45,6 +42,9 @@
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 /**
  * This sample demonstrates the implementation of self-signed CA's and connection to servers with
  * such certificates. Be sure to read 'res/raw/custom_ca.txt' for how-to instructions on how to
@@ -190,12 +190,12 @@ private void showCustomCAHelp() {
         builder.setTitle(R.string.title_custom_ca);
         builder.setMessage(getReadmeText());
         builder.setNeutralButton(android.R.string.cancel,
-            new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    dialog.dismiss();
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                    }
                 }
-            }
         );
         builder.show();
     }
diff --git a/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java b/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java
index 97d652bf9..9828894f7 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java
@@ -23,8 +23,8 @@
 import com.loopj.android.http.RequestHandle;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
 
 public class DeleteSample extends SampleParentActivity {
     private static final String LOG_TAG = "DeleteSample";
diff --git a/sample/src/main/java/com/loopj/android/http/sample/DigestAuthSample.java b/sample/src/main/java/com/loopj/android/http/sample/DigestAuthSample.java
index 14fa5a7f6..e4b64575a 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/DigestAuthSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/DigestAuthSample.java
@@ -8,10 +8,10 @@
 import com.loopj.android.http.RequestHandle;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+import cz.msebera.android.httpclient.auth.AuthScope;
+import cz.msebera.android.httpclient.auth.UsernamePasswordCredentials;
 
 public class DigestAuthSample extends GetSample {
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java
index 56bce8948..74c41ca2c 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java
@@ -30,11 +30,11 @@
 import com.loopj.android.http.ResponseHandlerInterface;
 import com.loopj.android.http.sample.util.FileUtil;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-
 import java.io.File;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 public class DirectorySample extends SampleParentActivity {
     private static final String LOG_TAG = "DirectorySample";
     private FileAsyncHttpResponseHandler lastResponseHandler = null;
diff --git a/sample/src/main/java/com/loopj/android/http/sample/FileSample.java b/sample/src/main/java/com/loopj/android/http/sample/FileSample.java
index 957cc9fe9..08637ea1c 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/FileSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/FileSample.java
@@ -26,11 +26,11 @@
 import com.loopj.android.http.ResponseHandlerInterface;
 import com.loopj.android.http.sample.util.FileUtil;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-
 import java.io.File;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 public class FileSample extends SampleParentActivity {
     private static final String LOG_TAG = "FileSample";
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java b/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java
index 1167aa4fa..6eff61066 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/FilesSample.java
@@ -7,14 +7,14 @@
 import com.loopj.android.http.RequestParams;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.util.Random;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 public class FilesSample extends PostSample {
 
     public static final String LOG_TAG = "FilesSample";
diff --git a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java
index 6b13f5a90..02e3880c0 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java
@@ -25,8 +25,8 @@
 import com.loopj.android.http.RequestHandle;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
 
 public class GetSample extends SampleParentActivity {
     private static final String LOG_TAG = "GetSample";
diff --git a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java
index c8bf4d3d4..06d32d171 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java
@@ -36,13 +36,13 @@
 import com.loopj.android.http.ResponseHandlerInterface;
 import com.loopj.android.http.sample.util.SampleJSON;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.message.BasicHeader;
-
 import java.util.List;
 import java.util.Locale;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+import cz.msebera.android.httpclient.message.BasicHeader;
+
 /**
  * This sample demonstrates how to implement HTTP 401 Basic Authentication.
  *
diff --git a/sample/src/main/java/com/loopj/android/http/sample/IntentServiceSample.java b/sample/src/main/java/com/loopj/android/http/sample/IntentServiceSample.java
index 7b7dde623..718529d4a 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/IntentServiceSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/IntentServiceSample.java
@@ -11,8 +11,8 @@
 import com.loopj.android.http.sample.services.ExampleIntentService;
 import com.loopj.android.http.sample.util.IntentUtil;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
 
 public class IntentServiceSample extends SampleParentActivity {
 
@@ -31,18 +31,18 @@ public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
             // switch() doesn't support strings in older JDK.
-            if(ACTION_START.equals(action)) {
+            if (ACTION_START.equals(action)) {
                 clearOutputs();
                 addView(getColoredView(LIGHTBLUE, "Request started"));
-            } else if(ACTION_FINISH.equals(action)) {
+            } else if (ACTION_FINISH.equals(action)) {
                 addView(getColoredView(LIGHTBLUE, "Request finished"));
-            } else if(ACTION_CANCEL.equals(action)) {
+            } else if (ACTION_CANCEL.equals(action)) {
                 addView(getColoredView(LIGHTBLUE, "Request cancelled"));
-            } else if(ACTION_RETRY.equals(action)) {
+            } else if (ACTION_RETRY.equals(action)) {
                 addView(getColoredView(LIGHTBLUE, "Request retried"));
-            } else if(ACTION_FAILURE.equals(action) || ACTION_SUCCESS.equals(action)) {
+            } else if (ACTION_FAILURE.equals(action) || ACTION_SUCCESS.equals(action)) {
                 debugThrowable(LOG_TAG, (Throwable) intent.getSerializableExtra(ExampleIntentService.INTENT_THROWABLE));
-                if(ACTION_SUCCESS.equals(action)) {
+                if (ACTION_SUCCESS.equals(action)) {
                     debugStatusCode(LOG_TAG, intent.getIntExtra(ExampleIntentService.INTENT_STATUS_CODE, 0));
                     debugHeaders(LOG_TAG, IntentUtil.deserializeHeaders(intent.getStringArrayExtra(ExampleIntentService.INTENT_HEADERS)));
                     byte[] returnedBytes = intent.getByteArrayExtra(ExampleIntentService.INTENT_DATA);
diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java
index 2858e914a..87442e1ec 100755
--- a/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java
@@ -26,8 +26,8 @@
 import com.loopj.android.http.ResponseHandlerInterface;
 import com.loopj.android.http.sample.util.SampleJSON;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
 
 public class JsonSample extends SampleParentActivity {
 
diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java
index d05cf2233..91b660f73 100644
--- a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java
+++ b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java
@@ -26,17 +26,18 @@
 import com.loopj.android.http.RequestParams;
 import com.loopj.android.http.ResponseHandlerInterface;
 
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.util.Iterator;
 
+import cz.msebera.android.httpclient.Header;
+import cz.msebera.android.httpclient.HttpEntity;
+
 /**
  * This sample demonstrates how to upload JSON data using streams, resulting
  * in a low-memory footprint even with extremely large data.
- *
+ * 

* Please note: You must prepare a server-side end-point to consume the uploaded * data. This is because the data is uploaded using "application/json" content * type and regular methods, expecting a multi-form content type, will fail to diff --git a/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java b/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java index 8bd8ab1e2..10926a551 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PatchSample.java @@ -1,45 +1,45 @@ package com.loopj.android.http.sample; -import org.apache.http.Header; -import org.apache.http.HttpEntity; - import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; + public class PatchSample extends SampleParentActivity { - private static final String LOG_TAG = "PatchSample"; - - @Override - public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { - return client.patch(this, URL, entity, null, responseHandler); - } + private static final String LOG_TAG = "PatchSample"; + + @Override + public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { + return client.patch(this, URL, entity, null, responseHandler); + } + + @Override + public int getSampleTitle() { + return R.string.title_patch_sample; + } - @Override - public int getSampleTitle() { - return R.string.title_patch_sample; - } + @Override + public boolean isRequestBodyAllowed() { + return false; + } - @Override - public boolean isRequestBodyAllowed() { - return false; - } + @Override + public boolean isRequestHeadersAllowed() { + return false; + } - @Override - public boolean isRequestHeadersAllowed() { - return false; - } + @Override + public String getDefaultURL() { + return PROTOCOL + "httpbin.org/patch"; + } - @Override - public String getDefaultURL() { - return PROTOCOL + "httpbin.org/patch"; - } - - @Override - public ResponseHandlerInterface getResponseHandler() { - return new AsyncHttpResponseHandler() { + @Override + public ResponseHandlerInterface getResponseHandler() { + return new AsyncHttpResponseHandler() { @Override public void onStart() { clearOutputs(); @@ -62,7 +62,7 @@ public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Th } } }; - } + } } diff --git a/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java b/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java index 4c7270de6..4be1c222d 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java @@ -22,7 +22,6 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; - import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.BaseJsonHttpResponseHandler; import com.loopj.android.http.PersistentCookieStore; @@ -30,9 +29,9 @@ import com.loopj.android.http.ResponseHandlerInterface; import com.loopj.android.http.sample.util.SampleJSON; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.client.CookieStore; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.client.CookieStore; public class PersistentCookiesSample extends SampleParentActivity { @@ -72,7 +71,7 @@ public String getDefaultURL() { String url = PROTOCOL + "httpbin.org/cookies"; // If the cookie store is empty, suggest a cookie. - if(cookieStore.getCookies().isEmpty()) { + if (cookieStore.getCookies().isEmpty()) { url += "/set?time=" + System.currentTimeMillis(); } diff --git a/sample/src/main/java/com/loopj/android/http/sample/PostSample.java b/sample/src/main/java/com/loopj/android/http/sample/PostSample.java index 234887dc8..81ce90d93 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/PostSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PostSample.java @@ -23,8 +23,8 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; public class PostSample extends SampleParentActivity { private static final String LOG_TAG = "PostSample"; diff --git a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java index 2a7c5726c..04acb7ead 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java @@ -21,27 +21,28 @@ import android.content.Context; import android.graphics.Color; import android.util.Log; + import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpRequest; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; + import java.util.Locale; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.client.AbstractHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.HttpContext; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.HttpResponse; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; +import cz.msebera.android.httpclient.impl.client.AbstractHttpClient; +import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; +import cz.msebera.android.httpclient.protocol.HttpContext; public class PrePostProcessingSample extends SampleParentActivity { - private static final String LOG_TAG = "PrePostProcessingSample"; - protected static final int LIGHTGREY = Color.parseColor("#E0E0E0"); protected static final int DARKGREY = Color.parseColor("#888888"); + private static final String LOG_TAG = "PrePostProcessingSample"; @Override public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) { @@ -80,13 +81,13 @@ public ResponseHandlerInterface getResponseHandler() { @Override public void onPreProcessResponse(ResponseHandlerInterface instance, HttpResponse response) { debugProcessing(LOG_TAG, "Pre", - "Response is about to be pre-processed", LIGHTGREY); + "Response is about to be pre-processed", LIGHTGREY); } - @Override + @Override public void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response) { debugProcessing(LOG_TAG, "Post", - "Response is about to be post-processed", DARKGREY); + "Response is about to be post-processed", DARKGREY); } @Override @@ -119,7 +120,7 @@ protected void debugProcessing(String TAG, String state, String message, final i runOnUiThread(new Runnable() { @Override public void run() { - addView(getColoredView(color, debugMessage)); + addView(getColoredView(color, debugMessage)); } }); } @@ -133,13 +134,13 @@ public PrePostProcessRequest(AbstractHttpClient client, HttpContext httpContext, @Override public void onPreProcessRequest(AsyncHttpRequest request) { debugProcessing(LOG_TAG, "Pre", - "Request is about to be pre-processed", LIGHTGREY); + "Request is about to be pre-processed", LIGHTGREY); } @Override public void onPostProcessRequest(AsyncHttpRequest request) { debugProcessing(LOG_TAG, "Post", - "Request is about to be post-processed", DARKGREY); + "Request is about to be post-processed", DARKGREY); } } } diff --git a/sample/src/main/java/com/loopj/android/http/sample/PutSample.java b/sample/src/main/java/com/loopj/android/http/sample/PutSample.java index f93d383b1..6be80c5c0 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/PutSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PutSample.java @@ -23,8 +23,8 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; public class PutSample extends SampleParentActivity { private static final String LOG_TAG = "PutSample"; diff --git a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java index 21774e595..aecd8c5ef 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java @@ -27,19 +27,19 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.HttpUriRequest; - import java.io.File; import java.io.IOException; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; + /** * This sample demonstrates use of {@link RangeFileAsyncHttpResponseHandler} to * download a remote file in multiple requests. While this response handler * class handles file storage, it's up to the app itself to request all chunks * of the file. - * + *

* Also demonstrated a method to query the remote file's size prior to sending * the actual GET requests. This ensures that the remote server is actually * capable of supporting the "Range" header, necessary to make this sample work. diff --git a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java index 3a964f357..faf92cbfb 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java @@ -24,18 +24,17 @@ import com.loopj.android.http.AsyncHttpClient; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.DefaultHttpClient; +import cz.msebera.android.httpclient.client.HttpClient; +import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; public class Redirect302Sample extends GetSample { - private boolean enableRedirects = true; - private boolean enableRelativeRedirects = true; - private boolean enableCircularRedirects = true; - private static final int MENU_ENABLE_REDIRECTS = 10; private static final int MENU_ENABLE_CIRCULAR_REDIRECTS = 11; private static final int MENU_ENABLE_RELATIVE_REDIRECTs = 12; + private boolean enableRedirects = true; + private boolean enableRelativeRedirects = true; + private boolean enableCircularRedirects = true; @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java b/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java index 3341887c9..a753be40a 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RequestParamsDebug.java @@ -10,9 +10,6 @@ import com.loopj.android.http.TextHttpResponseHandler; import com.loopj.android.http.sample.util.API8Util; -import org.apache.http.Header; -import org.apache.http.HttpEntity; - import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -20,10 +17,12 @@ import java.util.Map; import java.util.Set; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; + public class RequestParamsDebug extends SampleParentActivity { public static final String LOG_TAG = "RequestParamsDebug"; - private EditText customParams; private static final String DEMO_RP_CONTENT = "array=java\n" + "array=C\n" + "list=blue\n" + @@ -32,6 +31,7 @@ public class RequestParamsDebug extends SampleParentActivity { "set=art\n" + "map=first_name\n" + "map=last_name\n"; + private EditText customParams; @Override public ResponseHandlerInterface getResponseHandler() { diff --git a/sample/src/main/java/com/loopj/android/http/sample/ResumeDownloadSample.java b/sample/src/main/java/com/loopj/android/http/sample/ResumeDownloadSample.java index f7d332a91..b81902849 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/ResumeDownloadSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/ResumeDownloadSample.java @@ -7,16 +7,16 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; - import java.io.File; import java.io.IOException; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; + public class ResumeDownloadSample extends SampleParentActivity { - private File downloadTarget; private static final String LOG_TAG = "ResumeDownloadSample"; + private File downloadTarget; private File getDownloadTarget() { try { diff --git a/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java b/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java index 8add61caa..24816064a 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java @@ -22,12 +22,13 @@ import android.widget.Toast; import com.loopj.android.http.AsyncHttpClient; + import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.ConnectionPoolTimeoutException; +import cz.msebera.android.httpclient.conn.ConnectTimeoutException; +import cz.msebera.android.httpclient.conn.ConnectionPoolTimeoutException; /** * This sample demonstrates use of @@ -62,12 +63,12 @@ protected void onCreate(Bundle savedInstanceState) { protected void onResume() { super.onResume(); - if(!wasToastShown) { + if (!wasToastShown) { wasToastShown = true; Toast.makeText( - this, - "Exceptions' whitelist and blacklist updated\nSee RetryRequestSample.java for details", - Toast.LENGTH_LONG + this, + "Exceptions' whitelist and blacklist updated\nSee RetryRequestSample.java for details", + Toast.LENGTH_LONG ).show(); } } diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java b/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java index 18cbca1ea..3af2fed0d 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java @@ -19,18 +19,19 @@ package com.loopj.android.http.sample; import android.content.Context; + import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpRequest; import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; - import java.util.List; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.HttpContext; + +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; +import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; +import cz.msebera.android.httpclient.protocol.HttpContext; public interface SampleInterface { diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java index 6accb5570..ddb3e43a6 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java @@ -41,14 +41,6 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicHeader; -import org.apache.http.protocol.HttpContext; - import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; @@ -57,8 +49,30 @@ import java.util.List; import java.util.Locale; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; +import cz.msebera.android.httpclient.client.methods.HttpUriRequest; +import cz.msebera.android.httpclient.entity.StringEntity; +import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; +import cz.msebera.android.httpclient.message.BasicHeader; +import cz.msebera.android.httpclient.protocol.HttpContext; + public abstract class SampleParentActivity extends Activity implements SampleInterface { + protected static final String PROTOCOL_HTTP = "http://"; + protected static final String PROTOCOL_HTTPS = "https://"; + protected static final int LIGHTGREEN = Color.parseColor("#00FF66"); + protected static final int LIGHTRED = Color.parseColor("#FF3300"); + protected static final int YELLOW = Color.parseColor("#FFFF00"); + protected static final int LIGHTBLUE = Color.parseColor("#99CCFF"); + private static final String LOG_TAG = "SampleParentActivity"; + private static final int MENU_USE_HTTPS = 0; + private static final int MENU_CLEAR_VIEW = 1; + private static final int MENU_LOGGING_VERBOSITY = 2; + private static final int MENU_ENABLE_LOGGING = 3; + protected static String PROTOCOL = PROTOCOL_HTTPS; + private final List requestHandles = new LinkedList(); + public LinearLayout customFieldsLayout; private AsyncHttpClient asyncHttpClient = new AsyncHttpClient() { @Override @@ -70,27 +84,36 @@ protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpCon } }; private EditText urlEditText, headersEditText, bodyEditText; + protected final View.OnClickListener onClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.button_run: + onRunButtonPressed(); + break; + case R.id.button_cancel: + onCancelButtonPressed(); + break; + } + } + }; private LinearLayout responseLayout; - public LinearLayout customFieldsLayout; - private final List requestHandles = new LinkedList(); - private static final String LOG_TAG = "SampleParentActivity"; - - private static final int MENU_USE_HTTPS = 0; - private static final int MENU_CLEAR_VIEW = 1; - private static final int MENU_LOGGING_VERBOSITY = 2; - private static final int MENU_ENABLE_LOGGING = 3; - private boolean useHttps = true; private boolean enableLogging = true; - protected static final String PROTOCOL_HTTP = "http://"; - protected static final String PROTOCOL_HTTPS = "https://"; + protected static String throwableToString(Throwable t) { + if (t == null) + return null; - protected static String PROTOCOL = PROTOCOL_HTTPS; - protected static final int LIGHTGREEN = Color.parseColor("#00FF66"); - protected static final int LIGHTRED = Color.parseColor("#FF3300"); - protected static final int YELLOW = Color.parseColor("#FFFF00"); - protected static final int LIGHTBLUE = Color.parseColor("#99CCFF"); + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + return sw.toString(); + } + + public static int getContrastColor(int color) { + double y = (299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.blue(color)) / 1000; + return y >= 128 ? Color.BLACK : Color.WHITE; + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -225,20 +248,6 @@ public void onCancelButtonPressed() { asyncHttpClient.cancelRequests(SampleParentActivity.this, true); } - protected final View.OnClickListener onClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.button_run: - onRunButtonPressed(); - break; - case R.id.button_cancel: - onCancelButtonPressed(); - break; - } - } - }; - public List

getRequestHeadersList() { List
headers = new ArrayList
(); String headersRaw = headersEditText.getText() == null ? null : headersEditText.getText().toString(); @@ -326,15 +335,6 @@ protected final void debugHeaders(String TAG, Header[] headers) { } } - protected static String throwableToString(Throwable t) { - if (t == null) - return null; - - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - return sw.toString(); - } - protected final void debugThrowable(String TAG, Throwable t) { if (t != null) { Log.e(TAG, "AsyncHttpClient returned error", t); @@ -356,11 +356,6 @@ protected final void debugStatusCode(String TAG, int statusCode) { addView(getColoredView(LIGHTBLUE, msg)); } - public static int getContrastColor(int color) { - double y = (299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.blue(color)) / 1000; - return y >= 128 ? Color.BLACK : Color.WHITE; - } - protected View getColoredView(int bgColor, String msg) { TextView tv = new TextView(this); tv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); diff --git a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java index aa22c0b1c..0c5ecebff 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java @@ -23,23 +23,18 @@ import com.loopj.android.http.ResponseHandlerInterface; import com.loopj.android.http.SaxAsyncHttpResponseHandler; -import org.apache.http.Header; -import org.apache.http.HttpEntity; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; import java.util.ArrayList; import java.util.List; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; + public class SaxSample extends SampleParentActivity { private static final String LOG_TAG = "SaxSample"; - - @Override - public ResponseHandlerInterface getResponseHandler() { - return saxAsyncHttpResponseHandler; - } - private final SaxAsyncHttpResponseHandler saxAsyncHttpResponseHandler = new SaxAsyncHttpResponseHandler(new SAXTreeStructure()) { @Override public void onStart() { @@ -67,6 +62,11 @@ private void debugHandler(SAXTreeStructure handler) { } }; + @Override + public ResponseHandlerInterface getResponseHandler() { + return saxAsyncHttpResponseHandler; + } + @Override public String getDefaultURL() { return "http://bin-iin.com/sitemap.xml"; diff --git a/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java b/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java index 3f80ddb76..77ffcc60b 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java @@ -27,8 +27,8 @@ import com.loopj.android.http.ResponseHandlerInterface; import com.loopj.android.http.SyncHttpClient; -import org.apache.http.Header; -import org.apache.http.HttpEntity; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; public class SynchronousClientSample extends GetSample { private static final String LOG_TAG = "SyncSample"; diff --git a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java index 3bec476d9..815268335 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java @@ -25,8 +25,8 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; -import org.apache.http.HttpEntity; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.HttpEntity; public class ThreadingTimeoutSample extends SampleParentActivity { diff --git a/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java index 45dd61fdd..a9e6da958 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/UsePoolThreadSample.java @@ -5,10 +5,10 @@ import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.ResponseHandlerInterface; -import org.apache.http.Header; - import java.io.File; +import cz.msebera.android.httpclient.Header; + public class UsePoolThreadSample extends GetSample { private static final String LOG_TAG = "UsePoolThreadSample"; diff --git a/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java b/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java index 63e2ede27..5742e34e7 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java +++ b/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java @@ -10,7 +10,7 @@ import com.loopj.android.http.sample.IntentServiceSample; import com.loopj.android.http.sample.util.IntentUtil; -import org.apache.http.Header; +import cz.msebera.android.httpclient.Header; public class ExampleIntentService extends IntentService { diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/IntentUtil.java b/sample/src/main/java/com/loopj/android/http/sample/util/IntentUtil.java index a0ccb54b3..dadb8be59 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/util/IntentUtil.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/IntentUtil.java @@ -1,7 +1,7 @@ package com.loopj.android.http.sample.util; -import org.apache.http.Header; -import org.apache.http.message.BasicHeader; +import cz.msebera.android.httpclient.Header; +import cz.msebera.android.httpclient.message.BasicHeader; public class IntentUtil { diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java index a6380ccd1..1f55730b5 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java @@ -23,8 +23,6 @@ import com.loopj.android.http.AsyncHttpClient; -import org.apache.http.conn.ssl.SSLSocketFactory; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -49,6 +47,8 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import cz.msebera.android.httpclient.conn.ssl.SSLSocketFactory; + /** * A class to authenticate a secured connection against a custom CA using a BKS store. * @@ -168,10 +168,10 @@ public Socket createSocket(Socket socket, String host, int port, boolean autoClo injectHostname(socket, host); Socket sslSocket = sslCtx.getSocketFactory().createSocket(socket, host, port, autoClose); - + // throw an exception if the hostname does not match the certificate getHostnameVerifier().verify(host, (SSLSocket) sslSocket); - + return sslSocket; } diff --git a/sample/src/main/res/layout-v14/parent_layout.xml b/sample/src/main/res/layout-v14/parent_layout.xml index cef3029dd..bf796eb99 100755 --- a/sample/src/main/res/layout-v14/parent_layout.xml +++ b/sample/src/main/res/layout-v14/parent_layout.xml @@ -1,8 +1,8 @@ + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:fillViewport="true"> - + + android:inputType="textUri" /> + android:text="@string/button_cancel" />
*/ -@SuppressWarnings("ALL") +@SuppressWarnings("DesignForExtension") public abstract class AsyncHttpResponseHandler implements ResponseHandlerInterface { public static final String DEFAULT_CHARSET = "UTF-8"; diff --git a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java index 5db429ebf..f31065275 100644 --- a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java +++ b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java @@ -1,3 +1,20 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + https://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ package com.loopj.android.http; import cz.msebera.android.httpclient.Header; @@ -14,9 +31,6 @@ import cz.msebera.android.httpclient.protocol.HttpContext; import cz.msebera.android.httpclient.util.CharArrayBuffer; -/** - * Created by chase on 08/10/2015. - */ public class BearerAuthSchemeFactory implements AuthSchemeFactory { @Override diff --git a/library/src/main/java/com/loopj/android/http/TokenCredentials.java b/library/src/main/java/com/loopj/android/http/TokenCredentials.java index 10549aa45..7e8270bbe 100644 --- a/library/src/main/java/com/loopj/android/http/TokenCredentials.java +++ b/library/src/main/java/com/loopj/android/http/TokenCredentials.java @@ -1,8 +1,22 @@ +/* + Android Asynchronous Http Client + Copyright (c) 2011 James Smith + https://loopj.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ package com.loopj.android.http; -/** - * Created by chase on 08/10/2015. - */ import java.security.Principal; import cz.msebera.android.httpclient.auth.BasicUserPrincipal; From ff9633e3ac00b8aa864570abc640f4bcabf6a5a5 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Tue, 17 Nov 2015 17:20:55 +0100 Subject: [PATCH 124/167] Distributing proguard.txt in AAR packages --- library/build.gradle | 1 + library/proguard.txt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 library/proguard.txt diff --git a/library/build.gradle b/library/build.gradle index d463344f6..7a55b32cf 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -7,6 +7,7 @@ android { defaultConfig { minSdkVersion 3 targetSdkVersion 23 + consumerProguardFiles 'proguard.txt' } lintOptions { diff --git a/library/proguard.txt b/library/proguard.txt new file mode 100644 index 000000000..e3ab81252 --- /dev/null +++ b/library/proguard.txt @@ -0,0 +1,2 @@ +-keep class cz.msebera.android.httpclient.** { *; } +-keep class com.loopj.android.http.** { *; } From 9c7b6d41e3b84a5d62dfc914c29536708fc7dcdb Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Tue, 17 Nov 2015 17:50:01 +0100 Subject: [PATCH 125/167] Added HTTP OPTIONS call --- .../loopj/android/http/AsyncHttpClient.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 81e89c0f3..6644f5c26 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -58,6 +58,7 @@ import cz.msebera.android.httpclient.client.RedirectHandler; import cz.msebera.android.httpclient.client.methods.HttpEntityEnclosingRequestBase; import cz.msebera.android.httpclient.client.methods.HttpHead; +import cz.msebera.android.httpclient.client.methods.HttpOptions; import cz.msebera.android.httpclient.client.methods.HttpPatch; import cz.msebera.android.httpclient.client.methods.HttpPost; import cz.msebera.android.httpclient.client.methods.HttpPut; @@ -988,6 +989,24 @@ public void cancelRequestsByTAG(Object TAG, boolean mayInterruptIfRunning) { } // [-] HTTP HEAD + // [+] HTTP OPTIONS + + /** + * Perform a HTTP OPTIONS request, without any parameters. + * + * @param url the URL to send the request to. + * @param responseHandler the response handler instance that should handle the response. + * @return RequestHandle of future request process + */ + public RequestHandle options(String url, ResponseHandlerInterface responseHandler) { + return options(null, url, null, responseHandler); + } + + public RequestHandle options(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) { + return sendRequest(httpClient, httpContext, new HttpOptions(getUrlWithQueryString(isUrlEncodingEnabled(), url, params)), null, responseHandler, context); + } + + // [-] HTTP OPTIONS // [+] HTTP GET /** From d03630021b91636f333c40552c5a584d3029a0e2 Mon Sep 17 00:00:00 2001 From: MrTryp Date: Tue, 24 Nov 2015 11:36:15 +0100 Subject: [PATCH 126/167] test test --- test | 1 + 1 file changed, 1 insertion(+) create mode 100644 test diff --git a/test b/test new file mode 100644 index 000000000..9daeafb98 --- /dev/null +++ b/test @@ -0,0 +1 @@ +test From 61bf8c147898743d0356c47b7c84475707eab185 Mon Sep 17 00:00:00 2001 From: XYG6 Date: Tue, 24 Nov 2015 12:47:51 +0100 Subject: [PATCH 127/167] TLSv1.2 support with TLSv1 fallback Tries to use TLSv1.2 first on the HTTPS connection. If not available, falls back to TLSv1. --- .../android/http/MySSLSocketFactory.java | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 6d88a68d3..538ce4040 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -56,7 +56,17 @@ * certificate validation on every device, use with caution */ public class MySSLSocketFactory extends SSLSocketFactory { - final SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLContext sslContext; + + try { + sslContext = SSLContext.getInstance("TLSv1.2"); + } catch (NoSuchAlgorithmException e) { + // TODO fallback v1.1 if needed + Log_OC.w(TAG, "TLSv1.2 is not supported in this device; falling through TLSv1.0"); + sslContext = SSLContext.getInstance("TLSv1"); + // should be available in any device; see reference of supported protocols in + // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html + } /** * Creates a new SSL Socket Factory with the given KeyStore. @@ -186,13 +196,33 @@ public static DefaultHttpClient getNewHttpClient(KeyStore keyStore) { @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + Socket socket = sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + enableSecureProtocols(socket); + return socket; } @Override public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); + Socket socket = sslContext.getSocketFactory().createSocket(); + enableSecureProtocols(socket); + return socket; } + + /** + * Activate supported protocols on the socket. + * + * @param socket The socket on which to activate secure protocols. + */ + private void enableSecureProtocols(Socket socket) { + // get supported params + SSLParameters params = sslContext.getSupportedSSLParameters(); + String [] supportedProtocols = params.getProtocols(); + + // activate supported protocols on the socket + Socket socket = sslContext.getSocketFactory().createSocket(); + ((SSLSocket) socket).setEnabledProtocols(supportedProtocols); + //((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.2"} ); + } /** * Makes HttpsURLConnection trusts a set of certificates specified by the KeyStore From 288f5caa5e8edfb736a57e04415aeaba3c6859b5 Mon Sep 17 00:00:00 2001 From: Damien Date: Tue, 24 Nov 2015 13:07:48 +0100 Subject: [PATCH 128/167] Adding some logs --- .../main/java/com/loopj/android/http/MySSLSocketFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 538ce4040..9b62973c6 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -60,9 +60,10 @@ public class MySSLSocketFactory extends SSLSocketFactory { try { sslContext = SSLContext.getInstance("TLSv1.2"); + Log.w("SSLSocketFactory", "TLSv1.2 is supported"); } catch (NoSuchAlgorithmException e) { // TODO fallback v1.1 if needed - Log_OC.w(TAG, "TLSv1.2 is not supported in this device; falling through TLSv1.0"); + Log.w("SSLSocketFactory", "TLSv1.2 is not supported in this device; falling through TLSv1.0"); sslContext = SSLContext.getInstance("TLSv1"); // should be available in any device; see reference of supported protocols in // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html From 86e5a62cfe6b6322741017086edeb3c344e33386 Mon Sep 17 00:00:00 2001 From: damien Date: Tue, 24 Nov 2015 13:15:48 +0100 Subject: [PATCH 129/167] Fix --- .../src/main/java/com/loopj/android/http/MySSLSocketFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 9b62973c6..e67c06f34 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -36,6 +36,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import android.util.Log; import cz.msebera.android.httpclient.HttpVersion; import cz.msebera.android.httpclient.conn.ClientConnectionManager; From dcbf80f311dea4725ad7fadaf44e7c51699ebf8a Mon Sep 17 00:00:00 2001 From: XYG6 Date: Tue, 24 Nov 2015 13:58:09 +0100 Subject: [PATCH 130/167] FIX - MySSLSocketFactory wrong class structure --- .../android/http/MySSLSocketFactory.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index e67c06f34..8c929fc22 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -59,17 +59,6 @@ public class MySSLSocketFactory extends SSLSocketFactory { SSLContext sslContext; - try { - sslContext = SSLContext.getInstance("TLSv1.2"); - Log.w("SSLSocketFactory", "TLSv1.2 is supported"); - } catch (NoSuchAlgorithmException e) { - // TODO fallback v1.1 if needed - Log.w("SSLSocketFactory", "TLSv1.2 is not supported in this device; falling through TLSv1.0"); - sslContext = SSLContext.getInstance("TLSv1"); - // should be available in any device; see reference of supported protocols in - // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html - } - /** * Creates a new SSL Socket Factory with the given KeyStore. * @@ -81,6 +70,18 @@ public class MySSLSocketFactory extends SSLSocketFactory { */ public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); + + // Define sslContext + try { + sslContext = SSLContext.getInstance("TLSv1.2"); + Log.w("SSLSocketFactory", "TLSv1.2 is supported"); + } catch (NoSuchAlgorithmException e) { + // TODO fallback v1.1 if needed + Log.w("SSLSocketFactory", "TLSv1.2 is not supported in this device; falling through TLSv1.0"); + sslContext = SSLContext.getInstance("TLSv1"); + // should be available in any device; see reference of supported protocols in + // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html + } X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { From 0209f80757d8ee8932aac5dc95ad7725afd7579c Mon Sep 17 00:00:00 2001 From: XYG6 Date: Tue, 24 Nov 2015 14:37:33 +0100 Subject: [PATCH 131/167] FIX - missing try catch and wrong test min sdk version --- .../loopj/android/http/MySSLSocketFactory.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 8c929fc22..b2c1e90b3 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -34,6 +34,8 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import android.util.Log; @@ -199,9 +201,9 @@ public static DefaultHttpClient getNewHttpClient(KeyStore keyStore) { @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { - Socket socket = sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - enableSecureProtocols(socket); - return socket; + Socket localSocket = sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + enableSecureProtocols(localSocket); + return localSocket; } @Override @@ -222,8 +224,14 @@ private void enableSecureProtocols(Socket socket) { String [] supportedProtocols = params.getProtocols(); // activate supported protocols on the socket - Socket socket = sslContext.getSocketFactory().createSocket(); - ((SSLSocket) socket).setEnabledProtocols(supportedProtocols); + try { + Socket localSocket = sslContext.getSocketFactory().createSocket(); + ((SSLSocket) localSocket).setEnabledProtocols(supportedProtocols); + }catch (Exception e) + { + + } + //((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.2"} ); } From c7ebff882646d128365bb775d91cf33c11eedba6 Mon Sep 17 00:00:00 2001 From: XYG6 Date: Tue, 24 Nov 2015 17:02:22 +0100 Subject: [PATCH 132/167] REFACTORING - compress code --- library/build.gradle | 2 +- .../android/http/MySSLSocketFactory.java | 37 ++++--------------- sample/build.gradle | 2 +- 3 files changed, 9 insertions(+), 32 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 7a55b32cf..933f59d80 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,7 +5,7 @@ android { buildToolsVersion '23.0.1' defaultConfig { - minSdkVersion 3 + minSdkVersion 9 targetSdkVersion 23 consumerProguardFiles 'proguard.txt' } diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index b2c1e90b3..7b73a2eb5 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -59,7 +59,7 @@ * certificate validation on every device, use with caution */ public class MySSLSocketFactory extends SSLSocketFactory { - SSLContext sslContext; + final SSLContext sslContext = SSLContext.getInstance("TLS"); /** * Creates a new SSL Socket Factory with the given KeyStore. @@ -72,18 +72,6 @@ public class MySSLSocketFactory extends SSLSocketFactory { */ public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); - - // Define sslContext - try { - sslContext = SSLContext.getInstance("TLSv1.2"); - Log.w("SSLSocketFactory", "TLSv1.2 is supported"); - } catch (NoSuchAlgorithmException e) { - // TODO fallback v1.1 if needed - Log.w("SSLSocketFactory", "TLSv1.2 is not supported in this device; falling through TLSv1.0"); - sslContext = SSLContext.getInstance("TLSv1"); - // should be available in any device; see reference of supported protocols in - // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html - } X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { @@ -212,28 +200,17 @@ public Socket createSocket() throws IOException { enableSecureProtocols(socket); return socket; } - + /** * Activate supported protocols on the socket. - * + * * @param socket The socket on which to activate secure protocols. */ private void enableSecureProtocols(Socket socket) { - // get supported params + // set all supported protocols SSLParameters params = sslContext.getSupportedSSLParameters(); - String [] supportedProtocols = params.getProtocols(); - - // activate supported protocols on the socket - try { - Socket localSocket = sslContext.getSocketFactory().createSocket(); - ((SSLSocket) localSocket).setEnabledProtocols(supportedProtocols); - }catch (Exception e) - { - - } - - //((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.2"} ); - } + ((SSLSocket) socket).setEnabledProtocols(params.getProtocols()); + } /** * Makes HttpsURLConnection trusts a set of certificates specified by the KeyStore @@ -242,4 +219,4 @@ public void fixHttpsURLConnection() { HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); } -} +} \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index eb44af0e7..a97f1cf85 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -12,7 +12,7 @@ android { buildToolsVersion '23.0.1' defaultConfig { - minSdkVersion 3 + minSdkVersion 9 targetSdkVersion 23 } From 6721401ebabd01da7f6eb131c9a5871fbe3e1d9d Mon Sep 17 00:00:00 2001 From: XYG6 Date: Tue, 24 Nov 2015 17:08:15 +0100 Subject: [PATCH 133/167] CLEANUP --- .../main/java/com/loopj/android/http/MySSLSocketFactory.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 7b73a2eb5..a0ea08102 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -38,7 +38,6 @@ import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import android.util.Log; import cz.msebera.android.httpclient.HttpVersion; import cz.msebera.android.httpclient.conn.ClientConnectionManager; @@ -218,5 +217,4 @@ private void enableSecureProtocols(Socket socket) { public void fixHttpsURLConnection() { HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); } - } \ No newline at end of file From cdaf39e8d2d4b8fcd2323471edcf9f47666f0ea6 Mon Sep 17 00:00:00 2001 From: XYG6 Date: Tue, 24 Nov 2015 17:09:54 +0100 Subject: [PATCH 134/167] CLEANUP --- test | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test diff --git a/test b/test deleted file mode 100644 index 9daeafb98..000000000 --- a/test +++ /dev/null @@ -1 +0,0 @@ -test From 3ddb081adf934284f9db1adff82af8e8e88d6b43 Mon Sep 17 00:00:00 2001 From: Manan Date: Mon, 8 Feb 2016 18:50:01 +0530 Subject: [PATCH 135/167] Update README changed the incorrect repositories { maven { mavenCentral() } } to repositories { mavenCentral() } --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f56cbc1d6..4b375ec10 100755 --- a/README.md +++ b/README.md @@ -59,10 +59,9 @@ Packaging: JAR or AAR Gradle ```groovy repositories { - maven { - mavenCentral() - } + mavenCentral() } + dependencies { compile 'com.loopj.android:android-async-http:1.4.9' } From effd954e89e8467093fb046d0403e3ba467975f6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 26 Feb 2016 09:05:53 +0000 Subject: [PATCH 136/167] Set exception cause when re-raising IOException This allows to execute custom logic in AsyncHttpResponseHandler.onFailure for specific errors, e.g. to display a nicer error message to the user when there is a DNS resolution failure, instead of leaking a useless and verbose UnknownHostException in the UI. --- .../main/java/com/loopj/android/http/AsyncHttpRequest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index 1d92c9e2d..6113a9032 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -180,7 +180,7 @@ private void makeRequestWithRetries() throws IOException { // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry // (to assist in genuine cases of unknown host) which seems better than outright failure - cause = new IOException("UnknownHostException exception: " + e.getMessage()); + cause = new IOException("UnknownHostException exception: " + e.getMessage(), e); retry = (executionCount > 0) && retryHandler.retryRequest(e, ++executionCount, context); } catch (NullPointerException e) { // there's a bug in HttpClient 4.0.x that on some occasions causes @@ -203,7 +203,7 @@ private void makeRequestWithRetries() throws IOException { } catch (Exception e) { // catch anything else to ensure failure message is propagated AsyncHttpClient.log.e("AsyncHttpRequest", "Unhandled exception origin cause", e); - cause = new IOException("Unhandled exception: " + e.getMessage()); + cause = new IOException("Unhandled exception: " + e.getMessage(), cause); } // cleaned up to throw IOException From b9809956ca41031f1305cc67a9fc8c8b4632bb5b Mon Sep 17 00:00:00 2001 From: JoDa92 Date: Wed, 27 Apr 2016 08:53:53 +0200 Subject: [PATCH 137/167] Update RequestParams.java Changed ConcurrentHashMap to ConcurrentSkipHashMap for sorting feature --- .../com/loopj/android/http/RequestParams.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 0387b9285..b697f396e 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -33,7 +33,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipHashMap; import cz.msebera.android.httpclient.HttpEntity; import cz.msebera.android.httpclient.client.entity.UrlEncodedFormEntity; @@ -99,11 +99,11 @@ public class RequestParams implements Serializable { "application/json"; protected final static String LOG_TAG = "RequestParams"; - protected final ConcurrentHashMap urlParams = new ConcurrentHashMap(); - protected final ConcurrentHashMap streamParams = new ConcurrentHashMap(); - protected final ConcurrentHashMap fileParams = new ConcurrentHashMap(); - protected final ConcurrentHashMap> fileArrayParams = new ConcurrentHashMap>(); - protected final ConcurrentHashMap urlParamsWithObjects = new ConcurrentHashMap(); + protected final ConcurrentSkipHashMap urlParams = new ConcurrentSkipHashMap(); + protected final ConcurrentSkipHashMap streamParams = new ConcurrentSkipHashMap(); + protected final ConcurrentSkipHashMap fileParams = new ConcurrentSkipHashMap(); + protected final ConcurrentSkipHashMap> fileArrayParams = new ConcurrentSkipHashMap>(); + protected final ConcurrentSkipHashMap urlParamsWithObjects = new ConcurrentSkipHashMap(); protected boolean isRepeatable; protected boolean forceMultipartEntity = false; protected boolean useJsonStreamer; @@ -425,7 +425,7 @@ public boolean has(String key) { @Override public String toString() { StringBuilder result = new StringBuilder(); - for (ConcurrentHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -434,7 +434,7 @@ public String toString() { result.append(entry.getValue()); } - for (ConcurrentHashMap.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : streamParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -443,7 +443,7 @@ public String toString() { result.append("STREAM"); } - for (ConcurrentHashMap.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : fileParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -452,7 +452,7 @@ public String toString() { result.append("FILE"); } - for (ConcurrentHashMap.Entry> entry : fileArrayParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry> entry : fileArrayParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -530,22 +530,22 @@ private HttpEntity createJsonStreamerEntity(ResponseHandlerInterface progressHan elapsedFieldInJsonStreamer); // Add string params - for (ConcurrentHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add non-string params - for (ConcurrentHashMap.Entry entry : urlParamsWithObjects.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : urlParamsWithObjects.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add file params - for (ConcurrentHashMap.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : fileParams.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add stream params - for (ConcurrentHashMap.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : streamParams.entrySet()) { StreamWrapper stream = entry.getValue(); if (stream.inputStream != null) { entity.addPart(entry.getKey(), @@ -575,7 +575,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle entity.setIsRepeatable(isRepeatable); // Add string params - for (ConcurrentHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { entity.addPartWithCharset(entry.getKey(), entry.getValue(), contentEncoding); } @@ -586,7 +586,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle } // Add stream params - for (ConcurrentHashMap.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : streamParams.entrySet()) { StreamWrapper stream = entry.getValue(); if (stream.inputStream != null) { entity.addPart(entry.getKey(), stream.name, stream.inputStream, @@ -595,13 +595,13 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle } // Add file params - for (ConcurrentHashMap.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : fileParams.entrySet()) { FileWrapper fileWrapper = entry.getValue(); entity.addPart(entry.getKey(), fileWrapper.file, fileWrapper.contentType, fileWrapper.customFileName); } // Add file collection - for (ConcurrentHashMap.Entry> entry : fileArrayParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry> entry : fileArrayParams.entrySet()) { List fileWrapper = entry.getValue(); for (FileWrapper fw : fileWrapper) { entity.addPart(entry.getKey(), fw.file, fw.contentType, fw.customFileName); @@ -614,7 +614,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle protected List getParamsList() { List lparams = new LinkedList(); - for (ConcurrentHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { lparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } From e141b5cb92feadfa040c319858453ea8e4605255 Mon Sep 17 00:00:00 2001 From: JoDa92 Date: Thu, 28 Apr 2016 06:58:52 +0200 Subject: [PATCH 138/167] Update RequestParams.java --- .../com/loopj/android/http/RequestParams.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index b697f396e..cade5be69 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -33,7 +33,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentSkipHashMap; +import java.util.concurrent.ConcurrentSkipList; import cz.msebera.android.httpclient.HttpEntity; import cz.msebera.android.httpclient.client.entity.UrlEncodedFormEntity; @@ -99,11 +99,11 @@ public class RequestParams implements Serializable { "application/json"; protected final static String LOG_TAG = "RequestParams"; - protected final ConcurrentSkipHashMap urlParams = new ConcurrentSkipHashMap(); - protected final ConcurrentSkipHashMap streamParams = new ConcurrentSkipHashMap(); - protected final ConcurrentSkipHashMap fileParams = new ConcurrentSkipHashMap(); - protected final ConcurrentSkipHashMap> fileArrayParams = new ConcurrentSkipHashMap>(); - protected final ConcurrentSkipHashMap urlParamsWithObjects = new ConcurrentSkipHashMap(); + protected final ConcurrentSkipList urlParams = new ConcurrentSkipList(); + protected final ConcurrentSkipList streamParams = new ConcurrentSkipList(); + protected final ConcurrentSkipList fileParams = new ConcurrentSkipList(); + protected final ConcurrentSkipList> fileArrayParams = new ConcurrentSkipList>(); + protected final ConcurrentSkipList urlParamsWithObjects = new ConcurrentSkipList(); protected boolean isRepeatable; protected boolean forceMultipartEntity = false; protected boolean useJsonStreamer; @@ -425,7 +425,7 @@ public boolean has(String key) { @Override public String toString() { StringBuilder result = new StringBuilder(); - for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -434,7 +434,7 @@ public String toString() { result.append(entry.getValue()); } - for (ConcurrentSkipHashMap.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : streamParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -443,7 +443,7 @@ public String toString() { result.append("STREAM"); } - for (ConcurrentSkipHashMap.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : fileParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -452,7 +452,7 @@ public String toString() { result.append("FILE"); } - for (ConcurrentSkipHashMap.Entry> entry : fileArrayParams.entrySet()) { + for (ConcurrentSkipList.Entry> entry : fileArrayParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -530,22 +530,22 @@ private HttpEntity createJsonStreamerEntity(ResponseHandlerInterface progressHan elapsedFieldInJsonStreamer); // Add string params - for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add non-string params - for (ConcurrentSkipHashMap.Entry entry : urlParamsWithObjects.entrySet()) { + for (ConcurrentSkipList.Entry entry : urlParamsWithObjects.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add file params - for (ConcurrentSkipHashMap.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : fileParams.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add stream params - for (ConcurrentSkipHashMap.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : streamParams.entrySet()) { StreamWrapper stream = entry.getValue(); if (stream.inputStream != null) { entity.addPart(entry.getKey(), @@ -575,7 +575,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle entity.setIsRepeatable(isRepeatable); // Add string params - for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { entity.addPartWithCharset(entry.getKey(), entry.getValue(), contentEncoding); } @@ -586,7 +586,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle } // Add stream params - for (ConcurrentSkipHashMap.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : streamParams.entrySet()) { StreamWrapper stream = entry.getValue(); if (stream.inputStream != null) { entity.addPart(entry.getKey(), stream.name, stream.inputStream, @@ -595,13 +595,13 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle } // Add file params - for (ConcurrentSkipHashMap.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : fileParams.entrySet()) { FileWrapper fileWrapper = entry.getValue(); entity.addPart(entry.getKey(), fileWrapper.file, fileWrapper.contentType, fileWrapper.customFileName); } // Add file collection - for (ConcurrentSkipHashMap.Entry> entry : fileArrayParams.entrySet()) { + for (ConcurrentSkipList.Entry> entry : fileArrayParams.entrySet()) { List fileWrapper = entry.getValue(); for (FileWrapper fw : fileWrapper) { entity.addPart(entry.getKey(), fw.file, fw.contentType, fw.customFileName); @@ -614,7 +614,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle protected List getParamsList() { List lparams = new LinkedList(); - for (ConcurrentSkipHashMap.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { lparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } From 34a23f8d776d3a563172bada15459757e1df2656 Mon Sep 17 00:00:00 2001 From: BahadirBulduk Date: Tue, 11 Jul 2017 14:30:48 +0300 Subject: [PATCH 139/167] Fixing a security issue which is banned by google play. --- .../com/loopj/android/http/MySSLSocketFactory.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 6d88a68d3..fe5913b08 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -72,9 +72,19 @@ public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + try { + chain[0].checkValidity(); + } catch (Exception e) { + throw new CertificateException("Certificate not valid or trusted."); + } } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + try { + chain[0].checkValidity(); + } catch (Exception e) { + throw new CertificateException("Certificate not valid or trusted."); + } } public X509Certificate[] getAcceptedIssuers() { From 590a6f25b2bb975e0d3ecbe81f146a8d5776418a Mon Sep 17 00:00:00 2001 From: BahadirBulduk Date: Tue, 11 Jul 2017 14:50:56 +0300 Subject: [PATCH 140/167] Fixing a security issue which is banned by google play. --- library/build.gradle | 4 ++-- .../com/loopj/android/http/PersistentCookieStore.java | 8 ++++---- sample/build.gradle | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 7a55b32cf..943c394ea 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -2,10 +2,10 @@ apply plugin: 'com.android.library' android { compileSdkVersion 23 - buildToolsVersion '23.0.1' + buildToolsVersion '23.0.3' defaultConfig { - minSdkVersion 3 + minSdkVersion 9 targetSdkVersion 23 consumerProguardFiles 'proguard.txt' } diff --git a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java index b3419ea16..b290746b3 100755 --- a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java +++ b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java @@ -97,7 +97,7 @@ public void addCookie(Cookie cookie) { SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableCookie(cookie))); - prefsWriter.commit(); + prefsWriter.apply(); } @Override @@ -108,7 +108,7 @@ public void clear() { prefsWriter.remove(COOKIE_NAME_PREFIX + name); } prefsWriter.remove(COOKIE_NAME_STORE); - prefsWriter.commit(); + prefsWriter.apply(); // Clear cookies from local store cookies.clear(); @@ -138,7 +138,7 @@ public boolean clearExpired(Date date) { if (clearedAny) { prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); } - prefsWriter.commit(); + prefsWriter.apply(); return clearedAny; } @@ -168,7 +168,7 @@ public void deleteCookie(Cookie cookie) { cookies.remove(name); SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.remove(COOKIE_NAME_PREFIX + name); - prefsWriter.commit(); + prefsWriter.apply(); } /** diff --git a/sample/build.gradle b/sample/build.gradle index eb44af0e7..7f31e48d9 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -9,10 +9,10 @@ repositories { android { compileSdkVersion 23 - buildToolsVersion '23.0.1' + buildToolsVersion '23.0.3' defaultConfig { - minSdkVersion 3 + minSdkVersion 9 targetSdkVersion 23 } @@ -20,7 +20,7 @@ android { standard { } withLeakCanary { - minSdkVersion 8 + minSdkVersion 9 targetSdkVersion 23 } } From af920ded93c80a417825cace23542958d94ffc87 Mon Sep 17 00:00:00 2001 From: BahadirBulduk Date: Tue, 11 Jul 2017 14:55:35 +0300 Subject: [PATCH 141/167] upgraded travis ci build tools version to 23.0.3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c92d7a2cb..040454115 100755 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false jdk: openjdk7 android: components: - - build-tools-23.0.1 + - build-tools-23.0.3 - extra-android-support - extra-android-m2repository - android-23 From 26d135cd2858654ed4a5d65a6370694486751f30 Mon Sep 17 00:00:00 2001 From: BahadirBulduk Date: Tue, 11 Jul 2017 15:26:11 +0300 Subject: [PATCH 142/167] upgraded travis ci build tools version to 23.0.3 --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 040454115..ab2cbbd0d 100755 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,13 @@ sudo: false jdk: openjdk7 android: components: + - platform-tools + - tools - build-tools-23.0.3 - - extra-android-support - - extra-android-m2repository - android-23 + - extra-android-m2repository + - extra-google-m2repository + licenses: - '.+' script: From 9efecabe7dcbd293f09cffa84b2be825958ec840 Mon Sep 17 00:00:00 2001 From: Saeed_rz Date: Sat, 13 Jul 2019 13:20:27 +0430 Subject: [PATCH 143/167] fix issue #998 (#1317) * issue #998: update httpclient to fix unable resolve host issue * fix issue #998 update http client to fix unable resolve host issue * update project gradle version * change ConcurrentSkipList to ConcurrentSkipListMap - ConcurrentSkipList is unavailable in java anymore * remove buildToolsVersion and compileOptions to clear gradle warning * remove buildToolsVersion and compileOptions to clear gradle warning * fix productFlavors config to clear gradle error * change withLeakCanaryCompile to withLeakCanaryImplementation to clear gradle warning --- build.gradle | 7 +++- gradle/wrapper/gradle-wrapper.properties | 4 +- library/build.gradle | 8 +--- .../com/loopj/android/http/RequestParams.java | 39 ++++++++++--------- sample/build.gradle | 17 +++++--- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/build.gradle b/build.gradle index 2a500d66a..9e17ccfe0 100755 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,13 @@ buildscript { repositories { + jcenter() mavenCentral() + google() + } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:3.4.1' } } @@ -19,6 +22,8 @@ allprojects { repositories { mavenLocal() mavenCentral() + google() + } tasks.withType(JavaCompile) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3af41f22a..606898b47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jul 31 10:35:35 CEST 2015 +#Fri Jul 12 02:01:07 PDT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/library/build.gradle b/library/build.gradle index 943c394ea..f1b1a2d83 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -2,7 +2,6 @@ apply plugin: 'com.android.library' android { compileSdkVersion 23 - buildToolsVersion '23.0.3' defaultConfig { minSdkVersion 9 @@ -17,15 +16,10 @@ android { showAll true disable 'OldTargetApi' } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_6 - targetCompatibility JavaVersion.VERSION_1_6 - } } dependencies { - compile 'cz.msebera.android:httpclient:4.3.6' + compile 'cz.msebera.android:httpclient:4.5.8' } android.libraryVariants.all { variant -> diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index cade5be69..911b5d66f 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -33,7 +33,8 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentSkipList; +import java.util.concurrent.ConcurrentSkipListMap; +//import java.util.concurrent.ConcurrentSkipList; import cz.msebera.android.httpclient.HttpEntity; import cz.msebera.android.httpclient.client.entity.UrlEncodedFormEntity; @@ -99,11 +100,11 @@ public class RequestParams implements Serializable { "application/json"; protected final static String LOG_TAG = "RequestParams"; - protected final ConcurrentSkipList urlParams = new ConcurrentSkipList(); - protected final ConcurrentSkipList streamParams = new ConcurrentSkipList(); - protected final ConcurrentSkipList fileParams = new ConcurrentSkipList(); - protected final ConcurrentSkipList> fileArrayParams = new ConcurrentSkipList>(); - protected final ConcurrentSkipList urlParamsWithObjects = new ConcurrentSkipList(); + protected final ConcurrentSkipListMap urlParams = new ConcurrentSkipListMap(); + protected final ConcurrentSkipListMap streamParams = new ConcurrentSkipListMap(); + protected final ConcurrentSkipListMap fileParams = new ConcurrentSkipListMap(); + protected final ConcurrentSkipListMap> fileArrayParams = new ConcurrentSkipListMap>(); + protected final ConcurrentSkipListMap urlParamsWithObjects = new ConcurrentSkipListMap(); protected boolean isRepeatable; protected boolean forceMultipartEntity = false; protected boolean useJsonStreamer; @@ -425,7 +426,7 @@ public boolean has(String key) { @Override public String toString() { StringBuilder result = new StringBuilder(); - for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : urlParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -434,7 +435,7 @@ public String toString() { result.append(entry.getValue()); } - for (ConcurrentSkipList.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : streamParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -443,7 +444,7 @@ public String toString() { result.append("STREAM"); } - for (ConcurrentSkipList.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : fileParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -452,7 +453,7 @@ public String toString() { result.append("FILE"); } - for (ConcurrentSkipList.Entry> entry : fileArrayParams.entrySet()) { + for (ConcurrentSkipListMap.Entry> entry : fileArrayParams.entrySet()) { if (result.length() > 0) result.append("&"); @@ -530,22 +531,22 @@ private HttpEntity createJsonStreamerEntity(ResponseHandlerInterface progressHan elapsedFieldInJsonStreamer); // Add string params - for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : urlParams.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add non-string params - for (ConcurrentSkipList.Entry entry : urlParamsWithObjects.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : urlParamsWithObjects.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add file params - for (ConcurrentSkipList.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : fileParams.entrySet()) { entity.addPart(entry.getKey(), entry.getValue()); } // Add stream params - for (ConcurrentSkipList.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : streamParams.entrySet()) { StreamWrapper stream = entry.getValue(); if (stream.inputStream != null) { entity.addPart(entry.getKey(), @@ -575,7 +576,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle entity.setIsRepeatable(isRepeatable); // Add string params - for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : urlParams.entrySet()) { entity.addPartWithCharset(entry.getKey(), entry.getValue(), contentEncoding); } @@ -586,7 +587,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle } // Add stream params - for (ConcurrentSkipList.Entry entry : streamParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : streamParams.entrySet()) { StreamWrapper stream = entry.getValue(); if (stream.inputStream != null) { entity.addPart(entry.getKey(), stream.name, stream.inputStream, @@ -595,13 +596,13 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle } // Add file params - for (ConcurrentSkipList.Entry entry : fileParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : fileParams.entrySet()) { FileWrapper fileWrapper = entry.getValue(); entity.addPart(entry.getKey(), fileWrapper.file, fileWrapper.contentType, fileWrapper.customFileName); } // Add file collection - for (ConcurrentSkipList.Entry> entry : fileArrayParams.entrySet()) { + for (ConcurrentSkipListMap.Entry> entry : fileArrayParams.entrySet()) { List fileWrapper = entry.getValue(); for (FileWrapper fw : fileWrapper) { entity.addPart(entry.getKey(), fw.file, fw.contentType, fw.customFileName); @@ -614,7 +615,7 @@ private HttpEntity createMultipartEntity(ResponseHandlerInterface progressHandle protected List getParamsList() { List lparams = new LinkedList(); - for (ConcurrentSkipList.Entry entry : urlParams.entrySet()) { + for (ConcurrentSkipListMap.Entry entry : urlParams.entrySet()) { lparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } diff --git a/sample/build.gradle b/sample/build.gradle index 7f31e48d9..c598988bf 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -9,26 +9,31 @@ repositories { android { compileSdkVersion 23 - buildToolsVersion '23.0.3' defaultConfig { minSdkVersion 9 targetSdkVersion 23 } + flavorDimensions "version" productFlavors { standard { + dimension "version" + minSdkVersion 9 + targetSdkVersion 23 + } withLeakCanary { + dimension "version" minSdkVersion 9 targetSdkVersion 23 } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } +// compileOptions { +// sourceCompatibility 'JavaVersion.VERSION_1_7' +// targetCompatibility 'JavaVersion.VERSION_1_7' +// } lintOptions { xmlReport false @@ -49,5 +54,5 @@ dependencies { compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3' compile project(':library') // LeakCanary - withLeakCanaryCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' + withLeakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:1.3.1' } From 5629231a0765040b093115da3bec4cb80d9d57f7 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 13 Jul 2019 10:51:34 +0200 Subject: [PATCH 144/167] Travis CI Java 8 fixup --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab2cbbd0d..ae55dfa01 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: android sudo: false -jdk: openjdk7 +jdk: openjdk8 android: components: - platform-tools @@ -9,7 +9,6 @@ android: - android-23 - extra-android-m2repository - extra-google-m2repository - licenses: - '.+' script: From 7fad56ff284155bf8ce1d1038b1a46513f50b93b Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 13 Jul 2019 10:56:39 +0200 Subject: [PATCH 145/167] Travis CI Android SDK changes --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ae55dfa01..92008c2c9 100755 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ android: components: - platform-tools - tools - - build-tools-23.0.3 - - android-23 + - build-tools-28.0.3 + - android-28 - extra-android-m2repository - extra-google-m2repository licenses: From 6e888937cd4ff2ca861a84d06f6492ee33cae32a Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 13 Jul 2019 11:14:08 +0200 Subject: [PATCH 146/167] Lint fixes for newer SDK --- build.gradle | 2 +- library/build.gradle | 4 ++-- .../android/http/AsyncHttpResponseHandler.java | 5 +++-- sample/build.gradle | 15 +++++---------- .../http/sample/AsyncBackgroundThreadSample.java | 7 ++++--- .../http/sample/CancelRequestHandleSample.java | 10 ++++++---- .../android/http/sample/DirectorySample.java | 6 ++++-- .../com/loopj/android/http/sample/GetSample.java | 4 +++- .../com/loopj/android/http/sample/HeadSample.java | 8 +++++--- .../android/http/sample/Http401AuthSample.java | 2 +- .../android/http/sample/RangeResponseSample.java | 4 +++- .../android/http/sample/Redirect302Sample.java | 4 +++- .../android/http/sample/SampleParentActivity.java | 2 +- .../http/sample/ThreadingTimeoutSample.java | 4 +++- .../sample/services/ExampleIntentService.java | 4 +++- 15 files changed, 47 insertions(+), 34 deletions(-) diff --git a/build.gradle b/build.gradle index 9e17ccfe0..9fe5a37af 100755 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ allprojects { mavenLocal() mavenCentral() google() - + jcenter() } tasks.withType(JavaCompile) { diff --git a/library/build.gradle b/library/build.gradle index f1b1a2d83..45436ae0f 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 + compileSdkVersion 28 defaultConfig { minSdkVersion 9 - targetSdkVersion 23 + targetSdkVersion 28 consumerProguardFiles 'proguard.txt' } diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 88f105a20..68f60133d 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -26,6 +26,7 @@ import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URI; +import java.util.Locale; import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; @@ -241,7 +242,7 @@ public void setCharset(final String charset) { * @param totalSize total size of file */ public void onProgress(long bytesWritten, long totalSize) { - AsyncHttpClient.log.v(LOG_TAG, String.format("Progress %d from %d (%2.0f%%)", bytesWritten, totalSize, (totalSize > 0) ? (bytesWritten * 1.0 / totalSize) * 100 : -1)); + AsyncHttpClient.log.v(LOG_TAG, String.format(Locale.US, "Progress %d from %d (%2.0f%%)", bytesWritten, totalSize, (totalSize > 0) ? (bytesWritten * 1.0 / totalSize) * 100 : -1)); } /** @@ -294,7 +295,7 @@ public void onPostProcessResponse(ResponseHandlerInterface instance, HttpRespons * @param retryNo number of retry */ public void onRetry(int retryNo) { - AsyncHttpClient.log.d(LOG_TAG, String.format("Request retry no. %d", retryNo)); + AsyncHttpClient.log.d(LOG_TAG, String.format(Locale.US, "Request retry no. %d", retryNo)); } public void onCancel() { diff --git a/sample/build.gradle b/sample/build.gradle index c598988bf..23cffecc0 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -8,11 +8,11 @@ repositories { } android { - compileSdkVersion 23 + compileSdkVersion 28 defaultConfig { minSdkVersion 9 - targetSdkVersion 23 + targetSdkVersion 28 } flavorDimensions "version" @@ -20,27 +20,22 @@ android { standard { dimension "version" minSdkVersion 9 - targetSdkVersion 23 + targetSdkVersion 28 } withLeakCanary { dimension "version" minSdkVersion 9 - targetSdkVersion 23 + targetSdkVersion 28 } } -// compileOptions { -// sourceCompatibility 'JavaVersion.VERSION_1_7' -// targetCompatibility 'JavaVersion.VERSION_1_7' -// } - lintOptions { xmlReport false warningsAsErrors true quiet false showAll true - disable 'OldTargetApi', 'UnusedAttribute', 'LongLogTag' + disable 'OldTargetApi', 'UnusedAttribute', 'LongLogTag', 'TrustAllX509TrustManager', 'GoogleAppIndexingWarning', 'Autofill', 'LabelFor', 'SetTextI18n' } packagingOptions { diff --git a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java index 62589a3c0..c8a545910 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java @@ -33,6 +33,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; +import java.util.Locale; import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; @@ -109,7 +110,7 @@ public void onStart() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { - Log.d(LOG_TAG, String.format("onSuccess executing on main thread : %B", Looper.myLooper() == Looper.getMainLooper())); + Log.d(LOG_TAG, String.format(Locale.US, "onSuccess executing on main thread : %B", Looper.myLooper() == Looper.getMainLooper())); debugHeaders(LOG_TAG, headers); debugStatusCode(LOG_TAG, statusCode); debugResponse(LOG_TAG, new String(response)); @@ -117,7 +118,7 @@ public void onSuccess(int statusCode, Header[] headers, byte[] response) { @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { - Log.d(LOG_TAG, String.format("onFailure executing on main thread : %B", Looper.myLooper() == Looper.getMainLooper())); + Log.d(LOG_TAG, String.format(Locale.US, "onFailure executing on main thread : %B", Looper.myLooper() == Looper.getMainLooper())); debugHeaders(LOG_TAG, headers); debugStatusCode(LOG_TAG, statusCode); debugThrowable(LOG_TAG, e); @@ -129,7 +130,7 @@ public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Th @Override public void onRetry(int retryNo) { Toast.makeText(AsyncBackgroundThreadSample.this, - String.format("Request is retried, retry no. %d", retryNo), + String.format(Locale.US, "Request is retried, retry no. %d", retryNo), Toast.LENGTH_SHORT) .show(); } diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java index 5266a50e1..306dcb37d 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java @@ -20,6 +20,8 @@ import android.util.Log; +import java.util.Locale; + import com.loopj.android.http.RequestHandle; public class CancelRequestHandleSample extends ThreadingTimeoutSample { @@ -33,14 +35,14 @@ public int getSampleTitle() { @Override public void onCancelButtonPressed() { - Log.d(LOG_TAG, String.format("Number of handles found: %d", getRequestHandles().size())); + Log.d(LOG_TAG, String.format(Locale.US, "Number of handles found: %d", getRequestHandles().size())); int counter = 0; for (RequestHandle handle : getRequestHandles()) { if (!handle.isCancelled() && !handle.isFinished()) { - Log.d(LOG_TAG, String.format("Cancelling handle %d", counter)); - Log.d(LOG_TAG, String.format("Handle %d cancel", counter) + (handle.cancel(true) ? " succeeded" : " failed")); + Log.d(LOG_TAG, String.format(Locale.US, "Cancelling handle %d", counter)); + Log.d(LOG_TAG, String.format(Locale.US, "Handle %d cancel", counter) + (handle.cancel(true) ? " succeeded" : " failed")); } else { - Log.d(LOG_TAG, String.format("Handle %d already non-cancellable", counter)); + Log.d(LOG_TAG, String.format(Locale.US, "Handle %d already non-cancellable", counter)); } counter++; } diff --git a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java index 74c41ca2c..29aed2a67 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java @@ -32,6 +32,8 @@ import java.io.File; +import java.util.Locale; + import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; @@ -71,8 +73,8 @@ public void onClick(View v) { clearOutputs(); if (lastResponseHandler != null) { File toBeDeleted = lastResponseHandler.getTargetFile(); - debugResponse(LOG_TAG, String.format("File was deleted? %b", toBeDeleted.delete())); - debugResponse(LOG_TAG, String.format("Delete file path: %s", toBeDeleted.getAbsolutePath())); + debugResponse(LOG_TAG, String.format(Locale.US, "File was deleted? %b", toBeDeleted.delete())); + debugResponse(LOG_TAG, String.format(Locale.US, "Delete file path: %s", toBeDeleted.getAbsolutePath())); } else { debugThrowable(LOG_TAG, new Error("You have to Run example first")); } diff --git a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java index 02e3880c0..f8bbffc34 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java @@ -25,6 +25,8 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; +import java.util.Locale; + import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; @@ -85,7 +87,7 @@ public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Th @Override public void onRetry(int retryNo) { Toast.makeText(GetSample.this, - String.format("Request is retried, retry no. %d", retryNo), + String.format(Locale.US, "Request is retried, retry no. %d", retryNo), Toast.LENGTH_SHORT) .show(); } diff --git a/sample/src/main/java/com/loopj/android/http/sample/HeadSample.java b/sample/src/main/java/com/loopj/android/http/sample/HeadSample.java index 43443970b..d3a6d0dcb 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/HeadSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/HeadSample.java @@ -23,6 +23,8 @@ import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; +import java.util.Locale; + public class HeadSample extends FileSample { private static final String LOG_TAG = "HeadSample"; @@ -34,12 +36,12 @@ public ResponseHandlerInterface getResponseHandler() { public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { debugStatusCode(LOG_TAG, statusCode); debugHeaders(LOG_TAG, headers); - debugResponse(LOG_TAG, String.format("Response of size: %d", responseBody == null ? 0 : responseBody.length)); + debugResponse(LOG_TAG, String.format(Locale.US, "Response of size: %d", responseBody == null ? 0 : responseBody.length)); } @Override public void onProgress(long bytesWritten, long totalSize) { - addView(getColoredView(LIGHTRED, String.format("Progress %d from %d", bytesWritten, totalSize))); + addView(getColoredView(LIGHTRED, String.format(Locale.US, "Progress %d from %d", bytesWritten, totalSize))); } @Override @@ -47,7 +49,7 @@ public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Thr debugStatusCode(LOG_TAG, statusCode); debugHeaders(LOG_TAG, headers); debugThrowable(LOG_TAG, throwable); - debugResponse(LOG_TAG, String.format("Response of size: %d", responseBody == null ? 0 : responseBody.length)); + debugResponse(LOG_TAG, String.format(Locale.US, "Response of size: %d", responseBody == null ? 0 : responseBody.length)); } }; } diff --git a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java index 06d32d171..01d71fa6b 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java @@ -188,7 +188,7 @@ public DialogRunnable(String realm) { String prefaceText = preface.getText().toString(); // Substitute placeholders, and re-set the value. - preface.setText(String.format(prefaceText, SECRET_USERNAME, SECRET_PASSWORD)); + preface.setText(String.format(Locale.US, prefaceText, SECRET_USERNAME, SECRET_PASSWORD)); } @Override diff --git a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java index aecd8c5ef..d5e4af94a 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java @@ -30,6 +30,8 @@ import java.io.File; import java.io.IOException; +import java.util.Locale; + import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; import cz.msebera.android.httpclient.client.methods.HttpUriRequest; @@ -75,7 +77,7 @@ protected void onDestroy() { // Remove temporary file. if (file != null) { if (!file.delete()) { - Log.e(LOG_TAG, String.format("Couldn't remove temporary file in path: %s", file.getAbsolutePath())); + Log.e(LOG_TAG, String.format(Locale.US, "Couldn't remove temporary file in path: %s", file.getAbsolutePath())); } file = null; } diff --git a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java index faf92cbfb..7e1bb6c78 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java @@ -27,6 +27,8 @@ import cz.msebera.android.httpclient.client.HttpClient; import cz.msebera.android.httpclient.impl.client.DefaultHttpClient; +import java.util.Locale; + public class Redirect302Sample extends GetSample { private static final int MENU_ENABLE_REDIRECTS = 10; @@ -89,7 +91,7 @@ public AsyncHttpClient getAsyncHttpClient() { HttpClient client = ahc.getHttpClient(); if (client instanceof DefaultHttpClient) { Toast.makeText(this, - String.format("redirects: %b\nrelative redirects: %b\ncircular redirects: %b", + String.format(Locale.US, "redirects: %b\nrelative redirects: %b\ncircular redirects: %b", enableRedirects, enableRelativeRedirects, enableCircularRedirects), Toast.LENGTH_SHORT ).show(); diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java index ddb3e43a6..2397d494f 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java @@ -263,7 +263,7 @@ public List
getRequestHeadersList() { String headerName = line.substring(0, equalSignPos).trim(); String headerValue = line.substring(1 + equalSignPos).trim(); - Log.d(LOG_TAG, String.format("Added header: [%s:%s]", headerName, headerValue)); + Log.d(LOG_TAG, String.format(Locale.US, "Added header: [%s:%s]", headerName, headerValue)); headers.add(new BasicHeader(headerName, headerValue)); } catch (Throwable t) { diff --git a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java index 815268335..d2c67a6c9 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java @@ -25,6 +25,8 @@ import com.loopj.android.http.RequestHandle; import com.loopj.android.http.ResponseHandlerInterface; +import java.util.Locale; + import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpEntity; @@ -64,7 +66,7 @@ protected synchronized void setStatus(int id, String status) { states.put(id, current == null ? status : current + "," + status); clearOutputs(); for (int i = 0; i < states.size(); i++) { - debugResponse(LOG_TAG, String.format("%d (from %d): %s", states.keyAt(i), getCounter(), states.get(states.keyAt(i)))); + debugResponse(LOG_TAG, String.format(Locale.US, "%d (from %d): %s", states.keyAt(i), getCounter(), states.get(states.keyAt(i)))); } } diff --git a/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java b/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java index 5742e34e7..53e069ec3 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java +++ b/sample/src/main/java/com/loopj/android/http/sample/services/ExampleIntentService.java @@ -10,6 +10,8 @@ import com.loopj.android.http.sample.IntentServiceSample; import com.loopj.android.http.sample.util.IntentUtil; +import java.util.Locale; + import cz.msebera.android.httpclient.Header; public class ExampleIntentService extends IntentService { @@ -73,7 +75,7 @@ public void onCancel() { @Override public void onRetry(int retryNo) { sendBroadcast(new Intent(IntentServiceSample.ACTION_RETRY)); - Log.d(LOG_TAG, String.format("onRetry: %d", retryNo)); + Log.d(LOG_TAG, String.format(Locale.US, "onRetry: %d", retryNo)); } @Override From d03cc7663902b80d535cd470307258593dc025b9 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 13 Jul 2019 11:50:49 +0200 Subject: [PATCH 147/167] Gradle compatibility fixes --- library/build.gradle | 4 ++-- sample/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 45436ae0f..62d5c94ca 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -19,7 +19,7 @@ android { } dependencies { - compile 'cz.msebera.android:httpclient:4.5.8' + api 'cz.msebera.android:httpclient:4.5.8' } android.libraryVariants.all { variant -> @@ -27,7 +27,7 @@ android.libraryVariants.all { variant -> def task = project.tasks.create "jar${name.capitalize()}", Jar task.dependsOn variant.javaCompile task.from variant.javaCompile.destinationDir - artifacts.add('archives', task); + artifacts.add('archives', task) } apply from: '../maven_push.gradle' diff --git a/sample/build.gradle b/sample/build.gradle index 23cffecc0..f07bda563 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -46,8 +46,8 @@ android { } dependencies { - compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3' - compile project(':library') + api 'com.fasterxml.jackson.core:jackson-databind:2.5.3' + api project(':library') // LeakCanary withLeakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:1.3.1' } From 10ac3b335254b26b7228953514cf55428b0e9be1 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 13 Jul 2019 11:55:27 +0200 Subject: [PATCH 148/167] Updated README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4b375ec10..a1ad1f725 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Asynchronous Http Client for Android ==================================== -[![Build Status](https://travis-ci.org/loopj/android-async-http.png?branch=master)](https://travis-ci.org/loopj/android-async-http) +[![Build Status](https://travis-ci.org/android-async-http/android-async-http.png?branch=master)](https://travis-ci.org/android-async-http/android-async-http) An asynchronous, callback-based Http client for Android built on top of Apache's [HttpClient](https://hc.apache.org/httpcomponents-client-ga/) libraries. @@ -9,14 +9,14 @@ Changelog See what is new in version 1.4.9 released on 19th September 2015 -https://github.com/loopj/android-async-http/blob/1.4.9/CHANGELOG.md +https://github.com/android-async-http/android-async-http/blob/1.4.9/CHANGELOG.md Javadoc ------- Latest Javadoc for 1.4.9 release are available here (also included in Maven repository): -https://loopj.com/android-async-http/doc/ +https://android-async-http.github.io/android-async-http/doc/ Features -------- @@ -35,7 +35,7 @@ Examples -------- For inspiration and testing on device we've provided Sample Application. -See individual samples [here on Github](https://github.com/loopj/android-async-http/tree/1.4.9/sample/src/main/java/com/loopj/android/http/sample) +See individual samples [here on Github](https://github.com/android-async-http/android-async-http/tree/1.4.9/sample/src/main/java/com/loopj/android/http/sample) To run Sample application, simply clone the repository and run this command, to install it on connected device ```java @@ -93,5 +93,5 @@ Documentation, Features and Examples ------------------------------------ Full details and documentation can be found on the project page here: -https://loopj.com/android-async-http/ +https://android-async-http.github.io/android-async-http/ From 86136cdf608c96755e7fb241fdb5df0e6ccc5715 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Thu, 18 Jul 2019 23:43:23 +0200 Subject: [PATCH 149/167] Prepared 1.4.10-SNAPSHOT release, replacing 1.5.0 which is currently being developed in separate branch --- CHANGELOG.md | 5 ++++- README.md | 4 ++-- build.gradle | 2 +- gradle.properties | 4 ++-- sample/src/main/AndroidManifest.xml | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f21beed..ca2ec6608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # CHANGELOG -## 1.5.0 (future release) +## 1.4.10 + + - Fixed IP/name resolution errors #998 + - Fixed SNI compatibility ## 1.4.9 (released 19. 9. 2015) diff --git a/README.md b/README.md index a1ad1f725..cbee04048 100755 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ https://oss.sonatype.org/content/repositories/snapshots/com/loopj/android/androi Maven URL: https://oss.sonatype.org/content/repositories/snapshots/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.5.0-SNAPSHOT +Version: 1.4.10-SNAPSHOT Packaging: JAR or AAR ``` Gradle @@ -85,7 +85,7 @@ repositories { } } dependencies { - compile 'com.loopj.android:android-async-http:1.5.0-SNAPSHOT' + compile 'com.loopj.android:android-async-http:1.4.10-SNAPSHOT' } ``` diff --git a/build.gradle b/build.gradle index 9fe5a37af..a5ece5534 100755 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.5.0-SNAPSHOT' + version = '1.4.10-SNAPSHOT' repositories { mavenLocal() diff --git a/gradle.properties b/gradle.properties index 103245293..6b061990e 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=1.5.0-SNAPSHOT -VERSION_CODE=150 +VERSION_NAME=1.4.10-SNAPSHOT +VERSION_CODE=1410 GROUP=com.loopj.android POM_DESCRIPTION=An Asynchronous HTTP Library for Android diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ba877e103..6c4b7b0bb 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="8" + android:versionName="1.4.10-SNAPSHOT"> From b9592e11929cb8626f839b4669277c9bee0507f9 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Fri, 19 Jul 2019 00:57:04 +0200 Subject: [PATCH 150/167] Applied gradle publish updates to publish 1.4.10-SNAPSHOT to maven snapshots --- build.gradle | 13 ++++--- library/build.gradle | 84 +++++++++++++++++++++++++++++++++++++------- sample/build.gradle | 14 ++------ settings.gradle | 4 +++ 4 files changed, 87 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index a5ece5534..fa33fcf86 100755 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,16 @@ buildscript { repositories { jcenter() - mavenCentral() google() - + maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.vanniktech:gradle-android-javadoc-plugin:0.4.0-SNAPSHOT' + classpath 'digital.wup:android-maven-publish:3.6.2' + classpath "gradle.plugin.com.dorongold.plugins:task-tree:1.4" } } @@ -20,16 +23,18 @@ allprojects { version = '1.4.10-SNAPSHOT' repositories { - mavenLocal() - mavenCentral() google() jcenter() + mavenCentral() } tasks.withType(JavaCompile) { options.encoding = "UTF-8" options.compilerArgs << "-Xlint:unchecked" + options.compilerArgs << "-Xlint:deprecation" } } apply plugin: 'android-reporting' +apply plugin: 'com.vanniktech.android.javadoc' +apply plugin: 'com.dorongold.task-tree' diff --git a/library/build.gradle b/library/build.gradle index 62d5c94ca..bdf0596ea 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'digital.wup.android-maven-publish' +apply plugin: 'signing' android { compileSdkVersion 28 @@ -22,20 +24,78 @@ dependencies { api 'cz.msebera.android:httpclient:4.5.8' } -android.libraryVariants.all { variant -> - def name = variant.buildType.name - def task = project.tasks.create "jar${name.capitalize()}", Jar - task.dependsOn variant.javaCompile - task.from variant.javaCompile.destinationDir - artifacts.add('archives', task) -} - -apply from: '../maven_push.gradle' +project.afterEvaluate { project -> -afterEvaluate { project -> android.libraryVariants.all { variant -> - tasks.androidJavadocs.doFirst { - classpath += files(variant.javaCompile.classpath.files) + def name = variant.buildType.name + def task = project.tasks.create "jar${name.capitalize()}", Jar + task.dependsOn variant.javaCompileProvider.get() + task.from variant.javaCompileProvider.get().destinationDir + } + + task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + archiveClassifier = 'sources' + } + + task javadocJar(type: Jar, dependsOn: tasks.findAll { task -> task.name.contains('Javadoc') }) { + archiveClassifier = 'javadoc' + from 'build/docs/javadoc/release/' + } + + publishing { + publications { + maven(MavenPublication) { + artifactId = POM_ARTIFACT_ID + artifact javadocJar + artifact sourcesJar + artifact jarRelease + from components.android + + pom { + name = POM_NAME + description = POM_DESCRIPTION + packaging = POM_PACKAGING + url = POM_URL + + scm { + connection = POM_SCM_CONNECTION + developerConnection = POM_SCM_DEV_CONNECTION + url = POM_SCM_URL + } + + licenses { + license { + name = POM_LICENCE_NAME + url = POM_LICENCE_URL + distribution = POM_LICENCE_DIST + } + } + } + + pom.name = POM_NAME + pom.description = POM_DESCRIPTION + pom.url = POM_URL + pom.packaging = POM_PACKAGING + } } + repositories { + maven { + def releaseUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + def snapshotUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + url = version.endsWith('SNAPSHOT') ? snapshotUrl : releaseUrl + credentials { + def NexusUsername = project.hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : '' + def NexusPassword = project.hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : '' + username NexusUsername + password NexusPassword + } + } + } + } + + signing { + sign publishing.publications.maven } } + diff --git a/sample/build.gradle b/sample/build.gradle index f07bda563..6f4172494 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -19,14 +19,6 @@ android { productFlavors { standard { dimension "version" - minSdkVersion 9 - targetSdkVersion 28 - - } - withLeakCanary { - dimension "version" - minSdkVersion 9 - targetSdkVersion 28 } } @@ -46,8 +38,6 @@ android { } dependencies { - api 'com.fasterxml.jackson.core:jackson-databind:2.5.3' - api project(':library') - // LeakCanary - withLeakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:1.3.1' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.5.3' + implementation project(':android-async-http') } diff --git a/settings.gradle b/settings.gradle index 612d9e44e..9a70f607b 100755 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,6 @@ include ':library' include ':sample' + +rootProject.name = 'android-async-http-project' +project(':library').name = 'android-async-http' +project(':sample').name = 'android-async-http-sample' From f7502df2972268b129824a98ef97e2eb78509950 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 20 Jul 2019 07:30:34 +0200 Subject: [PATCH 151/167] Version 1.4.10 release --- .travis.yml | 4 ---- README.md | 8 ++++---- build.gradle | 2 +- gradle.properties | 2 +- sample/src/main/AndroidManifest.xml | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92008c2c9..044942064 100755 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,4 @@ android: licenses: - '.+' script: - # Sonatype bypass - - echo "nexusUsername=dummy" >> library/gradle.properties - - echo "nexusPassword=dummy" >> library/gradle.properties - ./gradlew clean assemble check - - ./gradlew :library:androidJavadocs diff --git a/README.md b/README.md index cbee04048..69ef55bea 100755 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ https://repo1.maven.org/maven2/com/loopj/android/android-async-http/ Maven URL: https://repo1.maven.org/maven2/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.9 +Version: 1.4.10 Packaging: JAR or AAR ``` Gradle @@ -63,7 +63,7 @@ repositories { } dependencies { - compile 'com.loopj.android:android-async-http:1.4.9' + compile 'com.loopj.android:android-async-http:1.4.10' } ``` @@ -74,7 +74,7 @@ https://oss.sonatype.org/content/repositories/snapshots/com/loopj/android/androi Maven URL: https://oss.sonatype.org/content/repositories/snapshots/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.10-SNAPSHOT +Version: 1.4.11-SNAPSHOT Packaging: JAR or AAR ``` Gradle @@ -85,7 +85,7 @@ repositories { } } dependencies { - compile 'com.loopj.android:android-async-http:1.4.10-SNAPSHOT' + compile 'com.loopj.android:android-async-http:1.4.11-SNAPSHOT' } ``` diff --git a/build.gradle b/build.gradle index fa33fcf86..893672b95 100755 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.4.10-SNAPSHOT' + version = '1.4.10' repositories { google() diff --git a/gradle.properties b/gradle.properties index 6b061990e..d755ee7c6 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=1.4.10-SNAPSHOT +VERSION_NAME=1.4.10 VERSION_CODE=1410 GROUP=com.loopj.android diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 6c4b7b0bb..09ed764f8 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ + android:versionName="1.4.10"> From 0132f8b216d2b3479ac3e6bb4926018597a9ae97 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 20 Jul 2019 07:36:06 +0200 Subject: [PATCH 152/167] Travis trusty explicitly, xenial seems to have problems with openjdk --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 044942064..ddc10848e 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: android sudo: false +dist: trusty jdk: openjdk8 android: components: From 9b5d7acc71b6f99f71d7f5c1ec04715486c55683 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 20 Jul 2019 08:18:08 +0200 Subject: [PATCH 153/167] Maven requires developers to be listed in POM, release complete --- library/build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/build.gradle b/library/build.gradle index bdf0596ea..ad5aa9044 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -71,6 +71,13 @@ project.afterEvaluate { project -> distribution = POM_LICENCE_DIST } } + + developers { + developer { + id = 'mareksebera' + name = 'Marek Sebera' + } + } } pom.name = POM_NAME From ebc4389b929e5e778bd9d2168adeb4ed9196f8b4 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 20 Jul 2019 17:42:25 +0200 Subject: [PATCH 154/167] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca2ec6608..311e8074f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fixed IP/name resolution errors #998 - Fixed SNI compatibility + - Upgraded library HttpClient 4.5.8 from 4.3.6 ## 1.4.9 (released 19. 9. 2015) From 7c9fe66f00e1b34b43677baf5e757f7147cec7bf Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 20 Jul 2019 18:42:40 +0200 Subject: [PATCH 155/167] Updated readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 69ef55bea..cef07d2a5 100755 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ An asynchronous, callback-based Http client for Android built on top of Apache's Changelog --------- -See what is new in version 1.4.9 released on 19th September 2015 +See what is new in version 1.4.10 released on 20th July 2019 -https://github.com/android-async-http/android-async-http/blob/1.4.9/CHANGELOG.md +https://github.com/android-async-http/android-async-http/blob/1.4.10/CHANGELOG.md Javadoc ------- -Latest Javadoc for 1.4.9 release are available here (also included in Maven repository): +Latest Javadoc for 1.4.10 release are available here (also included in Maven repository): https://android-async-http.github.io/android-async-http/doc/ @@ -35,7 +35,7 @@ Examples -------- For inspiration and testing on device we've provided Sample Application. -See individual samples [here on Github](https://github.com/android-async-http/android-async-http/tree/1.4.9/sample/src/main/java/com/loopj/android/http/sample) +See individual samples [here on Github](https://github.com/android-async-http/android-async-http/tree/1.4.10/sample/src/main/java/com/loopj/android/http/sample) To run Sample application, simply clone the repository and run this command, to install it on connected device ```java From 19ff79cc13b4164360dc5dac1dbb67573d55f48e Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Mon, 22 Jul 2019 12:42:27 +0200 Subject: [PATCH 156/167] Updated links to project, license/notice, copyright links, POM definition in gradle.properties --- NOTICE.txt | 3 +++ gradle.properties | 8 ++++---- .../main/java/com/loopj/android/http/AsyncHttpClient.java | 6 +++--- .../java/com/loopj/android/http/AsyncHttpRequest.java | 2 +- .../com/loopj/android/http/AsyncHttpResponseHandler.java | 2 +- .../loopj/android/http/BaseJsonHttpResponseHandler.java | 2 +- .../com/loopj/android/http/BearerAuthSchemeFactory.java | 2 +- .../com/loopj/android/http/BinaryHttpResponseHandler.java | 2 +- .../loopj/android/http/DataAsyncHttpResponseHandler.java | 2 +- .../loopj/android/http/FileAsyncHttpResponseHandler.java | 2 +- .../src/main/java/com/loopj/android/http/HttpDelete.java | 2 +- library/src/main/java/com/loopj/android/http/HttpGet.java | 2 +- .../com/loopj/android/http/JsonHttpResponseHandler.java | 2 +- .../java/com/loopj/android/http/JsonStreamerEntity.java | 2 +- .../java/com/loopj/android/http/JsonValueInterface.java | 2 +- .../java/com/loopj/android/http/MyRedirectHandler.java | 2 +- .../java/com/loopj/android/http/MySSLSocketFactory.java | 2 +- .../com/loopj/android/http/PersistentCookieStore.java | 2 +- .../PreemptiveAuthorizationHttpRequestInterceptor.java | 2 +- .../android/http/RangeFileAsyncHttpResponseHandler.java | 2 +- .../main/java/com/loopj/android/http/RequestHandle.java | 2 +- .../main/java/com/loopj/android/http/RequestParams.java | 2 +- .../com/loopj/android/http/ResponseHandlerInterface.java | 2 +- .../main/java/com/loopj/android/http/RetryHandler.java | 2 +- .../loopj/android/http/SaxAsyncHttpResponseHandler.java | 2 +- .../java/com/loopj/android/http/SerializableCookie.java | 2 +- .../com/loopj/android/http/SimpleMultipartEntity.java | 2 +- .../main/java/com/loopj/android/http/SyncHttpClient.java | 2 +- .../com/loopj/android/http/TextHttpResponseHandler.java | 2 +- .../java/com/loopj/android/http/TokenCredentials.java | 2 +- library/src/main/java/com/loopj/android/http/Utils.java | 2 +- .../main/java/com/loopj/android/http/package-info.java | 2 +- .../android/http/sample/AsyncBackgroundThreadSample.java | 2 +- .../java/com/loopj/android/http/sample/BinarySample.java | 2 +- .../android/http/sample/CancelAllRequestsSample.java | 2 +- .../android/http/sample/CancelRequestByTagSample.java | 2 +- .../android/http/sample/CancelRequestHandleSample.java | 2 +- .../com/loopj/android/http/sample/CustomCASample.java | 2 +- .../java/com/loopj/android/http/sample/DeleteSample.java | 2 +- .../com/loopj/android/http/sample/DirectorySample.java | 2 +- .../java/com/loopj/android/http/sample/FileSample.java | 2 +- .../java/com/loopj/android/http/sample/GetSample.java | 2 +- .../java/com/loopj/android/http/sample/GzipSample.java | 2 +- .../com/loopj/android/http/sample/Http401AuthSample.java | 2 +- .../java/com/loopj/android/http/sample/JsonSample.java | 2 +- .../com/loopj/android/http/sample/JsonStreamerSample.java | 2 +- .../android/http/sample/PersistentCookiesSample.java | 2 +- .../java/com/loopj/android/http/sample/PostSample.java | 2 +- .../android/http/sample/PrePostProcessingSample.java | 2 +- .../java/com/loopj/android/http/sample/PutSample.java | 2 +- .../loopj/android/http/sample/RangeResponseSample.java | 2 +- .../com/loopj/android/http/sample/Redirect302Sample.java | 2 +- .../com/loopj/android/http/sample/RetryRequestSample.java | 2 +- .../com/loopj/android/http/sample/SampleInterface.java | 2 +- .../loopj/android/http/sample/SampleParentActivity.java | 2 +- .../java/com/loopj/android/http/sample/SaxSample.java | 2 +- .../android/http/sample/SynchronousClientSample.java | 2 +- .../loopj/android/http/sample/ThreadingTimeoutSample.java | 2 +- .../com/loopj/android/http/sample/WaypointsActivity.java | 2 +- .../java/com/loopj/android/http/sample/package-info.java | 2 +- .../loopj/android/http/sample/services/package-info.java | 2 +- .../java/com/loopj/android/http/sample/util/FileUtil.java | 2 +- .../com/loopj/android/http/sample/util/SampleJSON.java | 2 +- .../android/http/sample/util/SecureSocketFactory.java | 2 +- .../com/loopj/android/http/sample/util/package-info.java | 2 +- 65 files changed, 72 insertions(+), 69 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index 45deb1012..792ce018f 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -2,5 +2,8 @@ Android Async Http Client library Copyright (c) 2011-2015 James Smith https://loopj.com +Copyright (c) 2015-2019 Marek Sebera +htts://msebera.cz + This product includes software developed by The Apache Software Foundation (https://www.apache.org/). diff --git a/gradle.properties b/gradle.properties index d755ee7c6..eae99249a 100755 --- a/gradle.properties +++ b/gradle.properties @@ -3,10 +3,10 @@ VERSION_CODE=1410 GROUP=com.loopj.android POM_DESCRIPTION=An Asynchronous HTTP Library for Android -POM_URL=https://loopj.com/android-async-http/ -POM_SCM_URL=https://github.com/loopj/android-async-http -POM_SCM_CONNECTION=scm:git@github.com:loopj/android-async-http.git -POM_SCM_DEV_CONNECTION=scm:git@github.com:loopj/android-async-http.git +POM_URL=https://android-async-http.github.io/android-async-http/ +POM_SCM_URL=https://github.com/android-async-http/android-async-http +POM_SCM_CONNECTION=scm:git@github.com:android-async-http/android-async-http.git +POM_SCM_DEV_CONNECTION=scm:git@github.com:android-async-http/android-async-http.git POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index 6644f5c26..e470257c5 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -3,7 +3,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -633,7 +633,7 @@ public void setRedirectHandler(final RedirectHandler customRedirectHandler) { /** * Sets the User-Agent header to be sent with each request. By default, "Android Asynchronous - * Http Client/VERSION (https://loopj.com/android-async-http/)" is used. + * Http Client/VERSION (https://github.com/android-async-http/android-async-http/)" is used. * * @param userAgent the string to use in the User-Agent header. */ @@ -1685,4 +1685,4 @@ public void consumeContent() throws IOException { super.consumeContent(); } } -} \ No newline at end of file +} diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java index 6113a9032..346cde73e 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpRequest.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java index 68f60133d..096020d9e 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java index f9d5f9182..69349f1d0 100755 --- a/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BaseJsonHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java index f31065275..3d17ea294 100644 --- a/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java +++ b/library/src/main/java/com/loopj/android/http/BearerAuthSchemeFactory.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java index 865fd5efe..2372a94e4 100755 --- a/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/BinaryHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java index bd5218668..a8d43a189 100755 --- a/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/DataAsyncHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java index 96bf9aea9..ee0d5b2c5 100755 --- a/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/FileAsyncHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/HttpDelete.java b/library/src/main/java/com/loopj/android/http/HttpDelete.java index 29d74d65d..5a426a76b 100644 --- a/library/src/main/java/com/loopj/android/http/HttpDelete.java +++ b/library/src/main/java/com/loopj/android/http/HttpDelete.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/HttpGet.java b/library/src/main/java/com/loopj/android/http/HttpGet.java index 548a4ae77..7fd882a52 100644 --- a/library/src/main/java/com/loopj/android/http/HttpGet.java +++ b/library/src/main/java/com/loopj/android/http/HttpGet.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java index b5bbe0a82..28af16d28 100755 --- a/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/JsonHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java index 56514bc7b..6fbee5040 100755 --- a/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java +++ b/library/src/main/java/com/loopj/android/http/JsonStreamerEntity.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/JsonValueInterface.java b/library/src/main/java/com/loopj/android/http/JsonValueInterface.java index e7b013622..303d96b22 100644 --- a/library/src/main/java/com/loopj/android/http/JsonValueInterface.java +++ b/library/src/main/java/com/loopj/android/http/JsonValueInterface.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java b/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java index 5ee6f6d0f..54f385ede 100644 --- a/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java +++ b/library/src/main/java/com/loopj/android/http/MyRedirectHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Aymon Fournier - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java index 212a81f09..7a2e6f432 100755 --- a/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java +++ b/library/src/main/java/com/loopj/android/http/MySSLSocketFactory.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java index b290746b3..8065d4821 100755 --- a/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java +++ b/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java index 09a265b69..806c7be25 100644 --- a/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java +++ b/library/src/main/java/com/loopj/android/http/PreemptiveAuthorizationHttpRequestInterceptor.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java index 2e6e8233d..f327a8caf 100755 --- a/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/RangeFileAsyncHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/RequestHandle.java b/library/src/main/java/com/loopj/android/http/RequestHandle.java index 6908ae93f..959190e13 100755 --- a/library/src/main/java/com/loopj/android/http/RequestHandle.java +++ b/library/src/main/java/com/loopj/android/http/RequestHandle.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2013 Jason Choy - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/RequestParams.java b/library/src/main/java/com/loopj/android/http/RequestParams.java index 911b5d66f..e594f7909 100755 --- a/library/src/main/java/com/loopj/android/http/RequestParams.java +++ b/library/src/main/java/com/loopj/android/http/RequestParams.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java index c5936fb43..4040a965b 100755 --- a/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java +++ b/library/src/main/java/com/loopj/android/http/ResponseHandlerInterface.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2013 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/RetryHandler.java b/library/src/main/java/com/loopj/android/http/RetryHandler.java index 6f519b9f4..c9e549a2b 100755 --- a/library/src/main/java/com/loopj/android/http/RetryHandler.java +++ b/library/src/main/java/com/loopj/android/http/RetryHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java index c13428626..8198fb549 100644 --- a/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/SaxAsyncHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/SerializableCookie.java b/library/src/main/java/com/loopj/android/http/SerializableCookie.java index 1801b536e..f6b88ffc0 100755 --- a/library/src/main/java/com/loopj/android/http/SerializableCookie.java +++ b/library/src/main/java/com/loopj/android/http/SerializableCookie.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java index a9c416793..2b4758f70 100755 --- a/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java +++ b/library/src/main/java/com/loopj/android/http/SimpleMultipartEntity.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/SyncHttpClient.java b/library/src/main/java/com/loopj/android/http/SyncHttpClient.java index 2d67f806e..dd7d8f532 100755 --- a/library/src/main/java/com/loopj/android/http/SyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/SyncHttpClient.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java index c2ffc7fa9..6b8aa67ed 100755 --- a/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java +++ b/library/src/main/java/com/loopj/android/http/TextHttpResponseHandler.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/TokenCredentials.java b/library/src/main/java/com/loopj/android/http/TokenCredentials.java index 7e8270bbe..aa361d395 100644 --- a/library/src/main/java/com/loopj/android/http/TokenCredentials.java +++ b/library/src/main/java/com/loopj/android/http/TokenCredentials.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/Utils.java b/library/src/main/java/com/loopj/android/http/Utils.java index d8311e992..3f56df33f 100644 --- a/library/src/main/java/com/loopj/android/http/Utils.java +++ b/library/src/main/java/com/loopj/android/http/Utils.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/library/src/main/java/com/loopj/android/http/package-info.java b/library/src/main/java/com/loopj/android/http/package-info.java index 7d6224e1e..1e99633ca 100644 --- a/library/src/main/java/com/loopj/android/http/package-info.java +++ b/library/src/main/java/com/loopj/android/http/package-info.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2011 James Smith - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java index c8a545910..3af0dbea7 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/AsyncBackgroundThreadSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java b/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java index fea76991d..73d47a5ad 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/BinarySample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java index ac69e69ac..7348e26e4 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelAllRequestsSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java index aab1ce744..38f1133bd 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestByTagSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java index 306dcb37d..e41a1d1be 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CancelRequestHandleSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java b/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java index faf14ffc2..2a3798ca2 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java b/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java index 9828894f7..69f443496 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/DeleteSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java index 29aed2a67..37b3f986d 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/DirectorySample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/FileSample.java b/sample/src/main/java/com/loopj/android/http/sample/FileSample.java index 08637ea1c..c06f9c480 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/FileSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/FileSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java index f8bbffc34..27b0be0e0 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/GetSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/GetSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java b/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java index 9025a3000..8da1c9372 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/GzipSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java index 01d71fa6b..93db38c3c 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Http401AuthSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java index 87442e1ec..59469ea9d 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/JsonSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java index 91b660f73..4d4d24d03 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/JsonStreamerSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java b/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java index 4be1c222d..69a72e2fb 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PersistentCookiesSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/PostSample.java b/sample/src/main/java/com/loopj/android/http/sample/PostSample.java index 81ce90d93..815961f04 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/PostSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PostSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java index 04acb7ead..654dab769 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PrePostProcessingSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/PutSample.java b/sample/src/main/java/com/loopj/android/http/sample/PutSample.java index 6be80c5c0..5cab76591 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/PutSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/PutSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java index d5e4af94a..e7f2e3e84 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RangeResponseSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java index 7e1bb6c78..832b6a6eb 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/Redirect302Sample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java b/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java index 24816064a..64c797c7f 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/RetryRequestSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java b/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java index 3af2fed0d..a259833c7 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleInterface.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java index 2397d494f..126d65bba 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java index 0c5ecebff..be310272c 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SaxSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java b/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java index 77ffcc60b..59ff04186 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SynchronousClientSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java index d2c67a6c9..f65ba17d8 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java +++ b/sample/src/main/java/com/loopj/android/http/sample/ThreadingTimeoutSample.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java index c963a0559..f1dba9d7a 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/WaypointsActivity.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/package-info.java b/sample/src/main/java/com/loopj/android/http/sample/package-info.java index c22f5a8d1..704f0d47d 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/package-info.java +++ b/sample/src/main/java/com/loopj/android/http/sample/package-info.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java b/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java index c7c54db2b..df7d33ef2 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java +++ b/sample/src/main/java/com/loopj/android/http/sample/services/package-info.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java b/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java index 18f4334df..faa9b7f5d 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/FileUtil.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java b/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java index e9f109415..60413e5ed 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/SampleJSON.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java index 1f55730b5..e7020367f 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Sample Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java b/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java index bc0c7263c..7d28904fd 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/package-info.java @@ -1,7 +1,7 @@ /* Android Asynchronous Http Client Copyright (c) 2014 Marek Sebera - https://loopj.com + https://github.com/android-async-http/android-async-http Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From ca93ab08f63c7adc6743cadb8031b719f4a71e3f Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Sun, 8 Sep 2019 14:47:22 +0430 Subject: [PATCH 157/167] change compile to implementation (#1322) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cef07d2a5..cb1ff5cad 100755 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ repositories { } dependencies { - compile 'com.loopj.android:android-async-http:1.4.10' + implementation 'com.loopj.android:android-async-http:1.4.10' } ``` @@ -85,7 +85,7 @@ repositories { } } dependencies { - compile 'com.loopj.android:android-async-http:1.4.11-SNAPSHOT' + implementation 'com.loopj.android:android-async-http:1.4.11-SNAPSHOT' } ``` From d57c60d6304fd06856bb81acf76e1c7581c286d4 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 28 Feb 2020 07:20:53 -0500 Subject: [PATCH 158/167] Official Gradle Wrapper Validation Action (#1330) See: https://github.com/gradle/wrapper-validation-action --- .github/workflows/gradle-wrapper-validation.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/workflows/gradle-wrapper-validation.yml diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml new file mode 100644 index 000000000..405a2b306 --- /dev/null +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -0,0 +1,10 @@ +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gradle/wrapper-validation-action@v1 From e14a642befd778d76f0ad8aeb293449acd37cb69 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Sat, 7 Mar 2020 11:41:57 +0100 Subject: [PATCH 159/167] deprecation notice --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index cb1ff5cad..9a03f9d45 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,34 @@ +# This project is no longer maintained, and is currently deprecated and insecure to use + +Since there were no active maintainers for this project for a long time, and issues got stale, +security issues pile up and it's not viable to maintain this project further, given there are +quality replacements, this project is closing down. + +This library has many issues handling modern TLS/SSL security protocols using and problems with validating +chain-of-trust of remote services, it communicates with. It also suffers from high-memory-usage issues, +when handling large upstream or downstream jobs. + +It is not suitable for modern projects, and thus, unless someone takes over the maintenance and invests big time +into making it performance and secure again, it is not recommended to use the library further. + +For issues with using this library or migrating to different one, use appropriate forum, for example +[https://stackoverflow.com/questions/tagged/android-async-http](https://stackoverflow.com/questions/tagged/android-async-http) + +## Use these alternatives, as replacement in your app please: + + - [OkHttp](https://square.github.io/okhttp/) https://square.github.io/okhttp/ + - [Volley](https://developer.android.com/training/volley) https://developer.android.com/training/volley + - [RetroFit](https://square.github.io/retrofit/) https://square.github.io/retrofit/ + +*or don't, i'm not a cop* + +--- +--- +--- +--- + + + Asynchronous Http Client for Android ==================================== [![Build Status](https://travis-ci.org/android-async-http/android-async-http.png?branch=master)](https://travis-ci.org/android-async-http/android-async-http) From 21ce76800520b5678dc61809ab8c8c01e1d90cdc Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Mon, 23 Mar 2020 04:37:53 -0700 Subject: [PATCH 160/167] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a03f9d45..9f8df0429 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# This project is no longer maintained, and is currently deprecated and insecure to use +# This project under develop, and is currently insecure to use Since there were no active maintainers for this project for a long time, and issues got stale, security issues pile up and it's not viable to maintain this project further, given there are From 027625fe1404761748061ccfe882c7cad8101f56 Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Wed, 24 Jun 2020 12:28:46 -0700 Subject: [PATCH 161/167] support Conscrypt (#1340) * add ConscryptSSLProvider to support sni on older android device * fix issue when using conscrypt after create client --- library/build.gradle | 1 + .../loopj/android/http/AsyncHttpClient.java | 8 ++++++++ .../android/http/ConscryptSSLProvider.java | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 library/src/main/java/com/loopj/android/http/ConscryptSSLProvider.java diff --git a/library/build.gradle b/library/build.gradle index ad5aa9044..d63952f0b 100755 --- a/library/build.gradle +++ b/library/build.gradle @@ -22,6 +22,7 @@ android { dependencies { api 'cz.msebera.android:httpclient:4.5.8' + compileOnly 'org.conscrypt:conscrypt-android:2.4.0' } project.afterEvaluate { project -> diff --git a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java index e470257c5..f38c4fe10 100755 --- a/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java +++ b/library/src/main/java/com/loopj/android/http/AsyncHttpClient.java @@ -1685,4 +1685,12 @@ public void consumeContent() throws IOException { super.consumeContent(); } } + + /** + * Call this method if your app target android below 4.4 + * This method enable sni in android below 4.4 + */ + public static void useConscryptSSLProvider(){ + ConscryptSSLProvider.install(); + } } diff --git a/library/src/main/java/com/loopj/android/http/ConscryptSSLProvider.java b/library/src/main/java/com/loopj/android/http/ConscryptSSLProvider.java new file mode 100644 index 000000000..67ee69060 --- /dev/null +++ b/library/src/main/java/com/loopj/android/http/ConscryptSSLProvider.java @@ -0,0 +1,18 @@ +package com.loopj.android.http; + +import android.util.Log; + +import org.conscrypt.Conscrypt; + +import java.security.Security; + +public class ConscryptSSLProvider { + public static void install(){ + try { + Security.insertProviderAt(Conscrypt.newProviderBuilder().build(),1); + }catch (NoClassDefFoundError ex){ + Log.e(AsyncHttpClient.LOG_TAG, "java.lang.NoClassDefFoundError: org.conscrypt.Conscrypt, Please add org.conscrypt.Conscrypt to your dependency"); + } + + } +} From d7d858c10d05d27109505ce055a83e30bd52dcad Mon Sep 17 00:00:00 2001 From: Saeedrz Date: Sun, 28 Jun 2020 23:00:36 -0700 Subject: [PATCH 162/167] upgrade gradle version to 6.1.1 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 893672b95..2eb6cbb57 100755 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.vanniktech:gradle-android-javadoc-plugin:0.4.0-SNAPSHOT' classpath 'digital.wup:android-maven-publish:3.6.2' classpath "gradle.plugin.com.dorongold.plugins:task-tree:1.4" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 606898b47..7bfd9f1e4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jul 12 02:01:07 PDT 2019 +#Sun Jun 28 22:59:06 PDT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip From 819c0e0cf76163223eb1999c998c28e8b29802ee Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Sun, 28 Jun 2020 23:21:16 -0700 Subject: [PATCH 163/167] Fix gradle warning (#1341) * remove unused if, sdk set always greater than 4 * Unnecessary; SDK_INT is always >= 9 * Use SDK_INT to easily get sdk as an integer * Unnecessary; SDK_INT is always >= 9 --- .../com/loopj/android/http/LogHandler.java | 6 +---- .../http/sample/SampleParentActivity.java | 2 +- .../http/sample/util/SecureSocketFactory.java | 9 +++----- .../http/sample/SampleApplication.java | 22 +++++++++---------- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/library/src/main/java/com/loopj/android/http/LogHandler.java b/library/src/main/java/com/loopj/android/http/LogHandler.java index dc7ffd2bc..2b7080a15 100644 --- a/library/src/main/java/com/loopj/android/http/LogHandler.java +++ b/library/src/main/java/com/loopj/android/http/LogHandler.java @@ -54,11 +54,7 @@ public void logWithThrowable(int logLevel, String tag, String msg, Throwable t) Log.d(tag, msg, t); break; case WTF: - if (Integer.valueOf(Build.VERSION.SDK) > 8) { - checkedWtf(tag, msg, t); - } else { - Log.e(tag, msg, t); - } + checkedWtf(tag, msg, t); break; case INFO: Log.i(tag, msg, t); diff --git a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java index 126d65bba..165b2baf8 100755 --- a/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java +++ b/sample/src/main/java/com/loopj/android/http/sample/SampleParentActivity.java @@ -394,7 +394,7 @@ public void setAsyncHttpClient(AsyncHttpClient client) { @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void setHomeAsUpEnabled() { - if (Integer.valueOf(Build.VERSION.SDK) >= 11) { + if (Build.VERSION.SDK_INT >= 11) { if (getActionBar() != null) getActionBar().setDisplayHomeAsUpEnabled(true); } diff --git a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java index e7020367f..fddcafcbe 100644 --- a/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java +++ b/sample/src/main/java/com/loopj/android/http/sample/util/SecureSocketFactory.java @@ -18,7 +18,6 @@ package com.loopj.android.http.sample.util; -import android.os.Build; import android.util.Log; import com.loopj.android.http.AsyncHttpClient; @@ -189,11 +188,9 @@ public Socket createSocket() throws IOException { */ private void injectHostname(Socket socket, String host) { try { - if (Integer.valueOf(Build.VERSION.SDK) >= 4) { - Field field = InetAddress.class.getDeclaredField("hostName"); - field.setAccessible(true); - field.set(socket.getInetAddress(), host); - } + Field field = InetAddress.class.getDeclaredField("hostName"); + field.setAccessible(true); + field.set(socket.getInetAddress(), host); } catch (Exception ignored) { } } diff --git a/sample/src/standard/java/com/loopj/android/http/sample/SampleApplication.java b/sample/src/standard/java/com/loopj/android/http/sample/SampleApplication.java index 2ef13dc0c..84522ce94 100644 --- a/sample/src/standard/java/com/loopj/android/http/sample/SampleApplication.java +++ b/sample/src/standard/java/com/loopj/android/http/sample/SampleApplication.java @@ -18,17 +18,15 @@ public void onCreate() { @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void setStrictMode() { - if (Integer.valueOf(Build.VERSION.SDK) > 3) { - Log.d(LOG_TAG, "Enabling StrictMode policy over Sample application"); - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .penaltyDeath() - .build()); - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); - } + Log.d(LOG_TAG, "Enabling StrictMode policy over Sample application"); + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() + .penaltyDeath() + .build()); + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() + .detectAll() + .penaltyLog() + .build()); } } From 01ea344166720cb059ace951b70753487ec25ce6 Mon Sep 17 00:00:00 2001 From: Marek Sebera Date: Mon, 29 Jun 2020 09:31:09 +0200 Subject: [PATCH 164/167] Release 1.4.11 along with publishing manual --- CHANGELOG.md | 4 +++ PUBLISHING.md | 48 +++++++++++++++++++++++++++++ README.md | 15 ++++----- build.gradle | 2 +- gradle.properties | 4 +-- sample/build.gradle | 2 +- sample/src/main/AndroidManifest.xml | 4 +-- 7 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 PUBLISHING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 311e8074f..72c4b65f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 1.4.11 + + - fix SNI issue on lower android device with Conscrypt + ## 1.4.10 - Fixed IP/name resolution errors #998 diff --git a/PUBLISHING.md b/PUBLISHING.md new file mode 100644 index 000000000..9ac180688 --- /dev/null +++ b/PUBLISHING.md @@ -0,0 +1,48 @@ +# Publish to oss.sonatype.org staging repository + +``` +gradle clean +# edit build.gradle to update allprojects.version +# edit gradle.properties to update VERSION_NAME and VERSION_CODE +# edit CHANGELOG.md and add changes for published version +# edit sample/src/main/AndroidManifest.xml and update both versionCode and versionName attributes +# edit README.md and update paths, latest version, repository links and sample codes +gradle check +# fix all possible errors and warnings before publishing +cd library +# publishing only library, so following tasks are run in "library" sub-folder +gradle generateJavadocJar +# this will create javadoc archive check the contents via following cmd (use different name and/or path if needed) +# jar -tf ./library/build/libs/android-async-http-null-Release-1.4.11-javadoc.jar +gradle publish +``` + +# Publish to maven central + +*For Nexus Repository Manager 2.14+* + + - Login into https://oss.sonatype.org/ + - Navigation, choose Build Promotion > Staging Repositories + - Explore if repo was automatically created and if contents do match expectations + - Select repository and use "Close" action, to run pre-publishing checks + - Wait a bit + - Refresh the panel with repositories + - Select repository and use "Release" action, if not available, there are issues, that need to be fixed before publishing + +# In GIT + + +**example code using 1.4.11 as released version** +``` +git tag 1.4.11 +git push origin --tags +``` + +# Github + +in *releases* https://github.com/android-async-http/android-async-http/releases + + - Create new release from appropriate tag (see GIT above) + - Describe in similar terms as in CHANGELOG.md what is being done + - Upload JAR (library, sources and javadoc) and AAR (library) along with the release + - Publish by saving form diff --git a/README.md b/README.md index 9f8df0429..25871358f 100755 --- a/README.md +++ b/README.md @@ -38,14 +38,14 @@ An asynchronous, callback-based Http client for Android built on top of Apache's Changelog --------- -See what is new in version 1.4.10 released on 20th July 2019 +See what is new in version 1.4.11 released on 29th June 2020 -https://github.com/android-async-http/android-async-http/blob/1.4.10/CHANGELOG.md +https://github.com/android-async-http/android-async-http/blob/1.4.11/CHANGELOG.md Javadoc ------- -Latest Javadoc for 1.4.10 release are available here (also included in Maven repository): +Latest Javadoc for 1.4.11 release are available here (also included in Maven repository): https://android-async-http.github.io/android-async-http/doc/ @@ -66,7 +66,7 @@ Examples -------- For inspiration and testing on device we've provided Sample Application. -See individual samples [here on Github](https://github.com/android-async-http/android-async-http/tree/1.4.10/sample/src/main/java/com/loopj/android/http/sample) +See individual samples [here on Github](https://github.com/android-async-http/android-async-http/tree/1.4.11/sample/src/main/java/com/loopj/android/http/sample) To run Sample application, simply clone the repository and run this command, to install it on connected device ```java @@ -84,7 +84,7 @@ https://repo1.maven.org/maven2/com/loopj/android/android-async-http/ Maven URL: https://repo1.maven.org/maven2/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.10 +Version: 1.4.11 Packaging: JAR or AAR ``` Gradle @@ -94,18 +94,19 @@ repositories { } dependencies { - implementation 'com.loopj.android:android-async-http:1.4.10' + implementation 'com.loopj.android:android-async-http:1.4.11' } ``` **development snapshots** +snapshot might not be published yet https://oss.sonatype.org/content/repositories/snapshots/com/loopj/android/android-async-http/ ``` Maven URL: https://oss.sonatype.org/content/repositories/snapshots/ GroupId: com.loopj.android ArtifactId: android-async-http -Version: 1.4.11-SNAPSHOT +Version: 1.4.12-SNAPSHOT Packaging: JAR or AAR ``` Gradle diff --git a/build.gradle b/build.gradle index 2eb6cbb57..2b8e1368e 100755 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ def isReleaseBuild() { allprojects { group = 'com.loopj.android' - version = '1.4.10' + version = '1.4.11' repositories { google() diff --git a/gradle.properties b/gradle.properties index eae99249a..c9086631a 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=1.4.10 -VERSION_CODE=1410 +VERSION_NAME=1.4.11 +VERSION_CODE=1411 GROUP=com.loopj.android POM_DESCRIPTION=An Asynchronous HTTP Library for Android diff --git a/sample/build.gradle b/sample/build.gradle index 6f4172494..a964a667f 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -38,6 +38,6 @@ android { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.5.3' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.0' implementation project(':android-async-http') } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 09ed764f8..3f4f13d4f 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="9" + android:versionName="1.4.11"> From 11a01738aca0923c9d38992bb2af23520325956c Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Thu, 2 Jul 2020 10:08:53 -0700 Subject: [PATCH 165/167] Update README.md --- README.md | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/README.md b/README.md index 25871358f..38c948f73 100755 --- a/README.md +++ b/README.md @@ -1,34 +1,3 @@ -# This project under develop, and is currently insecure to use - -Since there were no active maintainers for this project for a long time, and issues got stale, -security issues pile up and it's not viable to maintain this project further, given there are -quality replacements, this project is closing down. - -This library has many issues handling modern TLS/SSL security protocols using and problems with validating -chain-of-trust of remote services, it communicates with. It also suffers from high-memory-usage issues, -when handling large upstream or downstream jobs. - -It is not suitable for modern projects, and thus, unless someone takes over the maintenance and invests big time -into making it performance and secure again, it is not recommended to use the library further. - -For issues with using this library or migrating to different one, use appropriate forum, for example -[https://stackoverflow.com/questions/tagged/android-async-http](https://stackoverflow.com/questions/tagged/android-async-http) - -## Use these alternatives, as replacement in your app please: - - - [OkHttp](https://square.github.io/okhttp/) https://square.github.io/okhttp/ - - [Volley](https://developer.android.com/training/volley) https://developer.android.com/training/volley - - [RetroFit](https://square.github.io/retrofit/) https://square.github.io/retrofit/ - -*or don't, i'm not a cop* - ---- ---- ---- ---- - - - Asynchronous Http Client for Android ==================================== [![Build Status](https://travis-ci.org/android-async-http/android-async-http.png?branch=master)](https://travis-ci.org/android-async-http/android-async-http) @@ -61,6 +30,7 @@ Features - Automatic **gzip** response decoding support for super-fast requests - Optional built-in response parsing into **JSON** (JsonHttpResponseHandler) - Optional **persistent cookie store**, saves cookies into your app's SharedPreferences +- Support sni with Conscrypt on older android device Examples -------- From a443353a6dc2124ad5b05cfe8aa09deb5f2f9467 Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Wed, 5 Aug 2020 16:32:51 +0430 Subject: [PATCH 166/167] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38c948f73..1ff6c9f85 100755 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Features - Automatic **gzip** response decoding support for super-fast requests - Optional built-in response parsing into **JSON** (JsonHttpResponseHandler) - Optional **persistent cookie store**, saves cookies into your app's SharedPreferences -- Support sni with Conscrypt on older android device +- Support sni with Conscrypt on older android device ([wiki](https://github.com/android-async-http/android-async-http/wiki/Support-SNI-on-lower-android-device)) Examples -------- From 018a0b8d96a0dd569de9f8128cfe5d030e0423ef Mon Sep 17 00:00:00 2001 From: Saeed Rezaei Date: Mon, 18 Jan 2021 13:10:25 +0330 Subject: [PATCH 167/167] Apache license 2.0 (#1363) --- LICENSE.md | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.