From c5b66a9da762ebce64b358d7d6f7403da1470efd Mon Sep 17 00:00:00 2001 From: kbuckler Date: Fri, 14 Jul 2017 16:48:21 -0600 Subject: [PATCH 1/7] first commit --- README.md | 65 ++----------------------------------------- assets/Rx_Logo_S.png | Bin 0 -> 10259 bytes assets/rxjava2.png | Bin 69455 -> 0 bytes 3 files changed, 3 insertions(+), 62 deletions(-) create mode 100644 assets/Rx_Logo_S.png delete mode 100644 assets/rxjava2.png diff --git a/README.md b/README.md index 12a71f5..cbc3343 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,8 @@ - + -# Learning RxJava 2 for Android by example +# RxJava 2 for Android -[![Mindorks](https://img.shields.io/badge/mindorks-opensource-blue.svg)](https://mindorks.com/open-source-projects) -[![Mindorks Community](https://img.shields.io/badge/join-community-blue.svg)](https://mindorks.com/join-community) -[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-RxJava2%20Android%20Samples-blue.svg?style=flat)](https://android-arsenal.com/details/3/4314) -[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=102)](https://opensource.org/licenses/Apache-2.0) -[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/LICENSE) - -## How to use RxJava 2 in Android Application -## How to migrate from RxJava 1.0 to RxJava 2.0 - -### This project is for : -* who is migrating to RxJava 2 -* or just started with RxJava. - -### Just Build the project and start learning RxJava by examples. +### Built to learn RxJava2 RxJava 2.0 has been completely rewritten from scratch on top of the Reactive-Streams specification. The specification itself has evolved out of RxJava 1.x and provides a common baseline for reactive systems and libraries. @@ -104,49 +91,3 @@ RxJava1 -> RxJava2 * [PaginationActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java) - Pagination for loadMore in RecyclerView * [ComposeOperatorExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/compose/ComposeOperatorExampleActivity.java) - Compose operator for reusable -### TODO - -* Many examples are to be added - -### Find this project useful ? :heart: -* Support it by clicking the :star: button on the upper right of this page. :v: - -### Check out an awesome MVP architecture based project which uses RxJava2, Dagger2. -* [Android-MVP-Architecture](https://github.com/MindorksOpenSource/android-mvp-architecture) - -### Check out an awesome library for fast and simple networking in Android. -* [Fast Android Networking Library](https://github.com/amitshekhariitbhu/Fast-Android-Networking) - -### Another awesome library for debugging databases and shared preferences. -* [Android Debug Database](https://github.com/amitshekhariitbhu/Android-Debug-Database) - -### [Check out Mindorks awesome open source projects here](https://mindorks.com/open-source-projects) - -### Contact - Let's become friend -- [Twitter](https://twitter.com/amitiitbhu) -- [Github](https://github.com/amitshekhariitbhu) -- [Medium](https://medium.com/@amitshekhar) -- [Facebook](https://www.facebook.com/amit.shekhar.iitbhu) - -### License -``` - Copyright (C) 2016 Amit Shekhar - Copyright (C) 2011 Android Open Source Project - - 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. -``` - -### Contributing to RxJava 2 Android Samples -Just make pull request. You are in! - - diff --git a/assets/Rx_Logo_S.png b/assets/Rx_Logo_S.png new file mode 100644 index 0000000000000000000000000000000000000000..b4066e8a9bb70814bb1236a0f00ff48e0caaf521 GIT binary patch literal 10259 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 G_kRK3#&v4| From 8306458249b44541cec366c4fb4545410e5d4753 Mon Sep 17 00:00:00 2001 From: kbuckler Date: Fri, 14 Jul 2017 19:55:00 -0600 Subject: [PATCH 2/7] fix images and build --- README.md | 10 + android-networking/.gitignore | 1 + android-networking/build.gradle | 46 + android-networking/proguard-rules.pro | 20 + .../src/androidTest/AndroidManifest.xml | 24 + .../com/androidnetworking/GetJSONApiTest.java | 469 +++++ .../androidnetworking/GetObjectApiTest.java | 450 +++++ .../androidnetworking/GetStringApiTest.java | 348 ++++ .../MultipartJSONApiTest.java | 487 +++++ .../MultipartObjectApiTest.java | 467 +++++ .../MultipartStringApiTest.java | 371 ++++ .../androidnetworking/PostJSONApiTest.java | 499 +++++ .../androidnetworking/PostObjectApiTest.java | 480 +++++ .../androidnetworking/PostStringApiTest.java | 381 ++++ .../com/androidnetworking/model/User.java | 31 + .../src/main/AndroidManifest.xml | 20 + .../androidnetworking/AndroidNetworking.java | 312 +++ .../cache/LruBitmapCache.java | 59 + .../com/androidnetworking/cache/LruCache.java | 232 +++ .../androidnetworking/common/ANConstants.java | 36 + .../androidnetworking/common/ANRequest.java | 1712 +++++++++++++++++ .../androidnetworking/common/ANResponse.java | 73 + .../common/ConnectionClassManager.java | 120 ++ .../common/ConnectionQuality.java | 45 + .../com/androidnetworking/common/Method.java | 30 + .../androidnetworking/common/Priority.java | 54 + .../common/RequestBuilder.java | 69 + .../androidnetworking/common/RequestType.java | 27 + .../common/ResponseType.java | 31 + .../androidnetworking/core/ANExecutor.java | 113 ++ .../java/com/androidnetworking/core/Core.java | 52 + .../core/DefaultExecutorSupplier.java | 56 + .../core/ExecutorSupplier.java | 32 + .../core/MainThreadExecutor.java | 36 + .../core/PriorityThreadFactory.java | 53 + .../com/androidnetworking/error/ANError.java | 115 ++ .../gsonparserfactory/GsonParserFactory.java | 91 + .../GsonRequestBodyParser.java | 60 + .../GsonResponseBodyParser.java | 52 + .../interceptors/GzipRequestInterceptor.java | 92 + .../interceptors/HttpLoggingInterceptor.java | 302 +++ .../interfaces/AnalyticsListener.java | 27 + .../interfaces/BitmapRequestListener.java | 33 + .../ConnectionQualityChangeListener.java | 28 + .../interfaces/DownloadListener.java | 30 + .../interfaces/DownloadProgressListener.java | 25 + .../interfaces/JSONArrayRequestListener.java | 33 + .../interfaces/JSONObjectRequestListener.java | 33 + ...kHttpResponseAndBitmapRequestListener.java | 37 + ...tpResponseAndJSONArrayRequestListener.java | 37 + ...pResponseAndJSONObjectRequestListener.java | 37 + ...kHttpResponseAndParsedRequestListener.java | 35 + ...kHttpResponseAndStringRequestListener.java | 35 + .../interfaces/OkHttpResponseListener.java | 35 + .../interfaces/ParsedRequestListener.java | 33 + .../androidnetworking/interfaces/Parser.java | 60 + .../interfaces/StringRequestListener.java | 31 + .../interfaces/UploadProgressListener.java | 25 + .../internal/ANImageLoader.java | 371 ++++ .../internal/ANRequestQueue.java | 156 ++ .../internal/DownloadProgressHandler.java | 54 + .../internal/InternalNetworking.java | 317 +++ .../internal/InternalRunnable.java | 164 ++ .../internal/RequestProgressBody.java | 86 + .../internal/ResponseProgressBody.java | 88 + .../internal/SynchronousCall.java | 143 ++ .../internal/UploadProgressHandler.java | 54 + .../com/androidnetworking/model/Progress.java | 36 + .../androidnetworking/utils/ParseUtil.java | 48 + .../utils/SourceCloseUtil.java | 46 + .../com/androidnetworking/utils/Utils.java | 251 +++ .../androidnetworking/widget/ANImageView.java | 167 ++ .../src/main/res/values/strings.xml | 20 + .../androidnetworking/ExampleUnitTest.java | 32 + android-networking/upload.gradle | 101 + app/build.gradle | 1 - app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3418 -> 4186 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2206 -> 2254 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4842 -> 6040 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7718 -> 11516 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 10486 -> 17895 bytes build.gradle | 2 +- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- rx2-android-networking/.gitignore | 1 + rx2-android-networking/build.gradle | 48 + rx2-android-networking/proguard-rules.pro | 17 + rx2-android-networking/rx2-upload.gradle | 103 + .../src/androidTest/AndroidManifest.xml | 26 + .../Rx2GetJSONApiTest.java | 277 +++ .../Rx2GetObjectApiTest.java | 268 +++ .../Rx2GetStringApiTest.java | 160 ++ .../Rx2MultipartJSONApiTest.java | 281 +++ .../Rx2MultipartObjectApiTest.java | 272 +++ .../Rx2MultipartStringApiTest.java | 162 ++ .../Rx2PostJSONApiTest.java | 285 +++ .../Rx2PostObjectApiTest.java | 276 +++ .../Rx2PostStringApiTest.java | 164 ++ .../com/rx2androidnetworking/model/User.java | 31 + .../src/main/AndroidManifest.xml | 22 + .../rx2androidnetworking/Rx2ANRequest.java | 223 +++ .../Rx2AndroidNetworking.java | 120 ++ .../Rx2InternalNetworking.java | 441 +++++ .../src/main/res/values/strings.xml | 22 + .../rx2androidnetworking/ExampleUnitTest.java | 36 + settings.gradle | 2 +- 106 files changed, 13906 insertions(+), 6 deletions(-) create mode 100644 android-networking/.gitignore create mode 100644 android-networking/build.gradle create mode 100644 android-networking/proguard-rules.pro create mode 100755 android-networking/src/androidTest/AndroidManifest.xml create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/GetStringApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java create mode 100644 android-networking/src/androidTest/java/com/androidnetworking/model/User.java create mode 100644 android-networking/src/main/AndroidManifest.xml create mode 100644 android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java create mode 100644 android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java create mode 100644 android-networking/src/main/java/com/androidnetworking/cache/LruCache.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/ANConstants.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/ANRequest.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/ANResponse.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/Method.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/Priority.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/RequestType.java create mode 100644 android-networking/src/main/java/com/androidnetworking/common/ResponseType.java create mode 100644 android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java create mode 100644 android-networking/src/main/java/com/androidnetworking/core/Core.java create mode 100644 android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java create mode 100644 android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java create mode 100644 android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java create mode 100644 android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java create mode 100644 android-networking/src/main/java/com/androidnetworking/error/ANError.java create mode 100644 android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java create mode 100644 android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java create mode 100644 android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java create mode 100644 android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java create mode 100644 android-networking/src/main/java/com/androidnetworking/model/Progress.java create mode 100644 android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java create mode 100644 android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java create mode 100644 android-networking/src/main/java/com/androidnetworking/utils/Utils.java create mode 100644 android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java create mode 100644 android-networking/src/main/res/values/strings.xml create mode 100644 android-networking/src/test/java/com/androidnetworking/ExampleUnitTest.java create mode 100755 android-networking/upload.gradle mode change 100644 => 100755 app/src/main/res/mipmap-hdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-mdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xxhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 rx2-android-networking/.gitignore create mode 100644 rx2-android-networking/build.gradle create mode 100644 rx2-android-networking/proguard-rules.pro create mode 100755 rx2-android-networking/rx2-upload.gradle create mode 100755 rx2-android-networking/src/androidTest/AndroidManifest.xml create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java create mode 100644 rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java create mode 100644 rx2-android-networking/src/main/AndroidManifest.xml create mode 100644 rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java create mode 100644 rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java create mode 100644 rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java create mode 100644 rx2-android-networking/src/main/res/values/strings.xml create mode 100644 rx2-android-networking/src/test/java/com/rx2androidnetworking/ExampleUnitTest.java diff --git a/README.md b/README.md index cbc3343..99acf09 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # RxJava 2 for Android +### How to +Clone repo + +Clone https://github.com/businesstek/Fast-Android-Networking + +From RxJava2 Android Studio "File/New Module/Import Gradle Project" + +Only select modules "android-networking" and "rx2-android-networking" + +Note: original fork had network bug in gradle.properties ### Built to learn RxJava2 diff --git a/android-networking/.gitignore b/android-networking/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/android-networking/.gitignore @@ -0,0 +1 @@ +/build diff --git a/android-networking/build.gradle b/android-networking/build.gradle new file mode 100644 index 0000000..1750305 --- /dev/null +++ b/android-networking/build.gradle @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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. + */ + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion '25.0.0' + + defaultConfig { + minSdkVersion 9 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + consumerProguardFiles 'proguard-rules.pro' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.6.0' + compile 'com.squareup.okhttp3:okhttp:3.6.0' + compile 'com.google.code.gson:gson:2.8.0' +} +//apply from: 'upload.gradle' diff --git a/android-networking/proguard-rules.pro b/android-networking/proguard-rules.pro new file mode 100644 index 0000000..3f19523 --- /dev/null +++ b/android-networking/proguard-rules.pro @@ -0,0 +1,20 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/amitshekhar/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# For OkHttp +-dontwarn okio.** diff --git a/android-networking/src/androidTest/AndroidManifest.xml b/android-networking/src/androidTest/AndroidManifest.xml new file mode 100755 index 0000000..944071c --- /dev/null +++ b/android-networking/src/androidTest/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java new file mode 100644 index 0000000..57e8e33 --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java @@ -0,0 +1,469 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.JSONArrayRequestListener; +import com.androidnetworking.interfaces.JSONObjectRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONArrayRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONObjectRequestListener; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 03/04/17. + */ + +public class GetJSONApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public GetJSONApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testJSONObjectGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsJSONObject(new JSONObjectRequestListener() { + @Override + public void onResponse(JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONObjectGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsJSONObject(new JSONObjectRequestListener() { + @Override + public void onResponse(JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testJSONArrayGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsJSONArray(new JSONArrayRequestListener() { + @Override + public void onResponse(JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONArrayGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsJSONArray(new JSONArrayRequestListener() { + @Override + public void onResponse(JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONObjectGetRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForJSONObject(); + + assertEquals("Amit", response.getResult().getString("firstName")); + + assertEquals("Shekhar", response.getResult().getString("lastName")); + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONObjectGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForJSONObject(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONArrayGetRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForJSONArray(); + + JSONObject jsonObject = response.getResult().getJSONObject(0); + + assertEquals("Amit", jsonObject.getString("firstName")); + + assertEquals("Shekhar", jsonObject.getString("lastName")); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONArrayGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForJSONArray(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + public void testResponseBodyAndJSONObjectGet() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndJSONObjectGet404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testResponseBodyAndJSONArrayGet() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONArray(new OkHttpResponseAndJSONArrayRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndJSONArrayGet404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONArray(new OkHttpResponseAndJSONArrayRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} \ No newline at end of file diff --git a/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java new file mode 100644 index 0000000..e06a4ac --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java @@ -0,0 +1,450 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.OkHttpResponseAndParsedRequestListener; +import com.androidnetworking.interfaces.ParsedRequestListener; +import com.androidnetworking.model.User; + +import org.json.JSONException; +import org.junit.Rule; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 10/04/17. + */ + +public class GetObjectApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public GetObjectApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testObjectGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsObject(User.class, new ParsedRequestListener() { + @Override + public void onResponse(User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsObject(User.class, new ParsedRequestListener() { + @Override + public void onResponse(User user) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testObjectListGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsObjectList(User.class, new ParsedRequestListener>() { + @Override + public void onResponse(List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectListGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsObjectList(User.class, new ParsedRequestListener>() { + @Override + public void onResponse(List userList) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectGetRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForObject(User.class); + + assertEquals("Amit", response.getResult().firstName); + + assertEquals("Shekhar", response.getResult().lastName); + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForObject(User.class); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectListGetRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse> response = request.executeForObjectList(User.class); + + User user = response.getResult().get(0); + + assertEquals("Amit", user.firstName); + + assertEquals("Shekhar", user.lastName); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectListGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse> response = request.executeForObjectList(User.class); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + public void testResponseBodyAndObjectGet() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndObjectGet404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testResponseBodyAndObjectListGet() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObjectList(User.class, + new OkHttpResponseAndParsedRequestListener>() { + @Override + public void onResponse(Response okHttpResponse, List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndObjectListGet404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObjectList(User.class, + new OkHttpResponseAndParsedRequestListener>() { + @Override + public void onResponse(Response okHttpResponse, List userList) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} diff --git a/android-networking/src/androidTest/java/com/androidnetworking/GetStringApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/GetStringApiTest.java new file mode 100644 index 0000000..aaef6fe --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/GetStringApiTest.java @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.OkHttpResponseAndStringRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseListener; +import com.androidnetworking.interfaces.StringRequestListener; + +import org.junit.Rule; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +public class GetStringApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public GetStringApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testStringGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsString(new StringRequestListener() { + @Override + public void onResponse(String response) { + responseRef.set(response); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", responseRef.get()); + } + + public void testStringGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .build() + .getAsString(new StringRequestListener() { + @Override + public void onResponse(String response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousStringGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForString(); + + assertEquals("data", response.getResult()); + } + + @SuppressWarnings("unchecked") + public void testSynchronousStringGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForString(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + } + + public void testResponseBodyGet() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponse(new OkHttpResponseListener() { + @Override + public void onResponse(Response response) { + try { + responseRef.set(response.body().string()); + latch.countDown(); + } catch (IOException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", responseRef.get()); + } + + public void testResponseBodyGet404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponse(new OkHttpResponseListener() { + @Override + public void onResponse(Response response) { + try { + errorBodyRef.set(response.body().string()); + errorCodeRef.set(response.code()); + latch.countDown(); + } catch (IOException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + @SuppressWarnings("unchecked") + public void testSyncResponseBodyGet() throws InterruptedException, IOException { + + server.enqueue(new MockResponse().setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForOkHttpResponse(); + + assertEquals("data", response.getResult().body().string()); + + } + + @SuppressWarnings("unchecked") + public void testSyncResponseBodyGet404() throws InterruptedException, IOException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.get(server.url("/").toString()).build(); + + ANResponse response = request.executeForOkHttpResponse(); + + assertEquals("data", response.getResult().body().string()); + + assertEquals(404, response.getResult().code()); + } + + public void testResponseBodyAndStringGet() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final AtomicReference responseStringRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + responseBodySuccess.set(okHttpResponse.isSuccessful()); + responseStringRef.set(response); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("data", responseStringRef.get()); + } + + public void testResponseBodyAndStringGet404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.get(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + responseRef.set(response); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("data", responseRef.get()); + assertEquals("headerValue", headerRef.get()); + } +} \ No newline at end of file diff --git a/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java new file mode 100644 index 0000000..3fdc4cf --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java @@ -0,0 +1,487 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.JSONArrayRequestListener; +import com.androidnetworking.interfaces.JSONObjectRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONArrayRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONObjectRequestListener; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 09/04/17. + */ + +public class MultipartJSONApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public MultipartJSONApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testJSONObjectMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsJSONObject(new JSONObjectRequestListener() { + @Override + public void onResponse(JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONObjectMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsJSONObject(new JSONObjectRequestListener() { + @Override + public void onResponse(JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testJSONArrayMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsJSONArray(new JSONArrayRequestListener() { + @Override + public void onResponse(JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONArrayMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsJSONArray(new JSONArrayRequestListener() { + @Override + public void onResponse(JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONObjectMultipartRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForJSONObject(); + + assertEquals("Amit", response.getResult().getString("firstName")); + + assertEquals("Shekhar", response.getResult().getString("lastName")); + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONObjectMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForJSONObject(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONArrayMultipartRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForJSONArray(); + + JSONObject jsonObject = response.getResult().getJSONObject(0); + + assertEquals("Amit", jsonObject.getString("firstName")); + + assertEquals("Shekhar", jsonObject.getString("lastName")); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONArrayMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForJSONArray(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + public void testResponseBodyAndJSONObjectMultipart() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndJSONObjectMultipart404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testResponseBodyAndJSONArrayMultipart() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONArray(new OkHttpResponseAndJSONArrayRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndJSONArrayMultipart404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONArray(new OkHttpResponseAndJSONArrayRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + assertEquals("headerValue", headerRef.get()); + } + + +} diff --git a/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java new file mode 100644 index 0000000..e223381 --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java @@ -0,0 +1,467 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.OkHttpResponseAndParsedRequestListener; +import com.androidnetworking.interfaces.ParsedRequestListener; +import com.androidnetworking.model.User; + +import org.json.JSONException; +import org.junit.Rule; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 12/04/17. + */ + +public class MultipartObjectApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public MultipartObjectApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testObjectMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsObject(User.class, new ParsedRequestListener() { + @Override + public void onResponse(User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsObject(User.class, new ParsedRequestListener() { + @Override + public void onResponse(User user) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testObjectListMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsObjectList(User.class, new ParsedRequestListener>() { + @Override + public void onResponse(List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectListMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsObjectList(User.class, new ParsedRequestListener>() { + @Override + public void onResponse(List userList) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectMultipartRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForObject(User.class); + + assertEquals("Amit", response.getResult().firstName); + + assertEquals("Shekhar", response.getResult().lastName); + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForObject(User.class); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectListMultipartRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse> response = request.executeForObjectList(User.class); + + User user = response.getResult().get(0); + + assertEquals("Amit", user.firstName); + + assertEquals("Shekhar", user.lastName); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectListMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse> response = request.executeForObjectList(User.class); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + public void testResponseBodyAndObjectMultipart() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndObjectMultipart404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testResponseBodyAndObjectListMultipart() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObjectList(User.class, + new OkHttpResponseAndParsedRequestListener>() { + @Override + public void onResponse(Response okHttpResponse, List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndObjectListMultipart404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObjectList(User.class, + new OkHttpResponseAndParsedRequestListener>() { + @Override + public void onResponse(Response okHttpResponse, List userList) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} diff --git a/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java new file mode 100644 index 0000000..af01aa9 --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java @@ -0,0 +1,371 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.OkHttpResponseAndParsedRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndStringRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseListener; +import com.androidnetworking.interfaces.StringRequestListener; +import com.androidnetworking.model.User; + +import org.junit.Rule; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 27/03/17. + */ + +public class MultipartStringApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public MultipartStringApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testStringMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsString(new StringRequestListener() { + @Override + public void onResponse(String response) { + responseRef.set(response); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", responseRef.get()); + } + + public void testStringMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getAsString(new StringRequestListener() { + @Override + public void onResponse(String response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + @SuppressWarnings("unchecked") + public void testSynchronousStringMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForString(); + + assertEquals("data", response.getResult()); + } + + @SuppressWarnings("unchecked") + public void testSynchronousMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForString(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + } + + public void testResponseBodyMultipart() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponse(new OkHttpResponseListener() { + @Override + public void onResponse(Response response) { + try { + responseRef.set(response.body().string()); + latch.countDown(); + } catch (IOException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", responseRef.get()); + } + + public void testResponseBodyMultipart404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponse(new OkHttpResponseListener() { + @Override + public void onResponse(Response response) { + try { + errorBodyRef.set(response.body().string()); + errorCodeRef.set(response.code()); + latch.countDown(); + } catch (IOException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + @SuppressWarnings("unchecked") + public void testSyncResponseBodyMultipart() throws InterruptedException, IOException { + + server.enqueue(new MockResponse().setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForOkHttpResponse(); + + assertEquals("data", response.getResult().body().string()); + + } + + @SuppressWarnings("unchecked") + public void testSyncResponseBodyMultipart404() throws InterruptedException, IOException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build(); + + ANResponse response = request.executeForOkHttpResponse(); + + assertEquals("data", response.getResult().body().string()); + + assertEquals(404, response.getResult().code()); + } + + public void testResponseBodyAndStringMultipart() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final AtomicReference responseStringRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + responseBodySuccess.set(okHttpResponse.isSuccessful()); + responseStringRef.set(response); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("data", responseStringRef.get()); + } + + public void testResponseBodyAndStringMultipart404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.upload(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .addMultipartParameter("key", "value") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + responseRef.set(response); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("data", responseRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} \ No newline at end of file diff --git a/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java new file mode 100644 index 0000000..2f9a244 --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java @@ -0,0 +1,499 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.JSONArrayRequestListener; +import com.androidnetworking.interfaces.JSONObjectRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONArrayRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONObjectRequestListener; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 06/04/17. + */ + +public class PostJSONApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public PostJSONApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testJSONObjectPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsJSONObject(new JSONObjectRequestListener() { + @Override + public void onResponse(JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONObjectPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsJSONObject(new JSONObjectRequestListener() { + @Override + public void onResponse(JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testJSONArrayPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsJSONArray(new JSONArrayRequestListener() { + @Override + public void onResponse(JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONArrayPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsJSONArray(new JSONArrayRequestListener() { + @Override + public void onResponse(JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONObjectPostRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForJSONObject(); + + assertEquals("Amit", response.getResult().getString("firstName")); + + assertEquals("Shekhar", response.getResult().getString("lastName")); + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONObjectPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForJSONObject(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONArrayPostRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForJSONArray(); + + JSONObject jsonObject = response.getResult().getJSONObject(0); + + assertEquals("Amit", jsonObject.getString("firstName")); + + assertEquals("Shekhar", jsonObject.getString("lastName")); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousJSONArrayPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForJSONArray(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + public void testResponseBodyAndJSONObjectPost() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndJSONObjectPost404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testResponseBodyAndJSONArrayPost() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONArray(new OkHttpResponseAndJSONArrayRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndJSONArrayPost404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONArray(new OkHttpResponseAndJSONArrayRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndJSONObject(new OkHttpResponseAndJSONObjectRequestListener() { + @Override + public void onResponse(Response okHttpResponse, JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} diff --git a/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java new file mode 100644 index 0000000..2865436 --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java @@ -0,0 +1,480 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.OkHttpResponseAndParsedRequestListener; +import com.androidnetworking.interfaces.ParsedRequestListener; +import com.androidnetworking.model.User; + +import org.json.JSONException; +import org.junit.Rule; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 11/04/17. + */ + +public class PostObjectApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public PostObjectApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testObjectPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsObject(User.class, new ParsedRequestListener() { + @Override + public void onResponse(User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsObject(User.class, new ParsedRequestListener() { + @Override + public void onResponse(User user) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testObjectListPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsObjectList(User.class, new ParsedRequestListener>() { + @Override + public void onResponse(List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectListPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsObjectList(User.class, new ParsedRequestListener>() { + @Override + public void onResponse(List userList) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectPostRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForObject(User.class); + + assertEquals("Amit", response.getResult().firstName); + + assertEquals("Shekhar", response.getResult().lastName); + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForObject(User.class); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectListPostRequest() throws InterruptedException, JSONException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse> response = request.executeForObjectList(User.class); + + User user = response.getResult().get(0); + + assertEquals("Amit", user.firstName); + + assertEquals("Shekhar", user.lastName); + + } + + @SuppressWarnings("unchecked") + public void testSynchronousObjectListPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse> response = request.executeForObjectList(User.class); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + + } + + public void testResponseBodyAndObjectPost() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndObjectPost404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testResponseBodyAndObjectListPost() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObjectList(User.class, + new OkHttpResponseAndParsedRequestListener>() { + @Override + public void onResponse(Response okHttpResponse, List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testResponseBodyAndObjectListPost404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObjectList(User.class, + new OkHttpResponseAndParsedRequestListener>() { + @Override + public void onResponse(Response okHttpResponse, List userList) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndObject(User.class, + new OkHttpResponseAndParsedRequestListener() { + @Override + public void onResponse(Response okHttpResponse, User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} diff --git a/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java new file mode 100644 index 0000000..17b527a --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java @@ -0,0 +1,381 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.OkHttpResponseAndStringRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseListener; +import com.androidnetworking.interfaces.StringRequestListener; + +import org.junit.Rule; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 25/03/17. + */ + +public class PostStringApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public PostStringApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testStringPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsString(new StringRequestListener() { + @Override + public void onResponse(String response) { + responseRef.set(response); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", responseRef.get()); + } + + + public void testStringPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getAsString(new StringRequestListener() { + @Override + public void onResponse(String response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + @SuppressWarnings("unchecked") + public void testSynchronousStringPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForString(); + + assertEquals("data", response.getResult()); + } + + @SuppressWarnings("unchecked") + public void testSynchronousStringPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForString(); + + ANError error = response.getError(); + + assertEquals("data", error.getErrorBody()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, error.getErrorDetail()); + + assertEquals(404, error.getErrorCode()); + } + + public void testResponseBodyPost() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponse(new OkHttpResponseListener() { + @Override + public void onResponse(Response response) { + try { + responseRef.set(response.body().string()); + latch.countDown(); + } catch (IOException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", responseRef.get()); + } + + public void testResponseBodyPost404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponse(new OkHttpResponseListener() { + @Override + public void onResponse(Response response) { + try { + errorBodyRef.set(response.body().string()); + errorCodeRef.set(response.code()); + latch.countDown(); + } catch (IOException e) { + assertTrue(false); + } + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + @SuppressWarnings("unchecked") + public void testSyncResponseBodyPost() throws InterruptedException, IOException { + + server.enqueue(new MockResponse().setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForOkHttpResponse(); + + assertEquals("data", response.getResult().body().string()); + + } + + @SuppressWarnings("unchecked") + public void testSyncResponseBodyPost404() throws InterruptedException, IOException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + ANRequest request = AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build(); + + ANResponse response = request.executeForOkHttpResponse(); + + assertEquals("data", response.getResult().body().string()); + + assertEquals(404, response.getResult().code()); + } + + public void testResponseBodyAndStringPost() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final AtomicReference responseStringRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + responseBodySuccess.set(okHttpResponse.isSuccessful()); + responseStringRef.set(response); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("data", responseStringRef.get()); + } + + public void testResponseBodyAndStringPost404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference errorDetailRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + assertTrue(false); + } + + @Override + public void onError(ANError anError) { + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + } + + public void testHeaderPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final AtomicReference headerRef = new AtomicReference<>(); + final AtomicReference responseBodySuccess = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + AndroidNetworking.post(server.url("/").toString()) + .addHeaders("headerKey", "headerValue") + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .setExecutor(Executors.newSingleThreadExecutor()) + .build() + .getAsOkHttpResponseAndString(new OkHttpResponseAndStringRequestListener() { + @Override + public void onResponse(Response okHttpResponse, String response) { + responseRef.set(response); + responseBodySuccess.set(okHttpResponse.isSuccessful()); + headerRef.set(okHttpResponse.request().header("headerKey")); + latch.countDown(); + } + + @Override + public void onError(ANError anError) { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(responseBodySuccess.get()); + assertEquals("data", responseRef.get()); + assertEquals("headerValue", headerRef.get()); + } + +} diff --git a/android-networking/src/androidTest/java/com/androidnetworking/model/User.java b/android-networking/src/androidTest/java/com/androidnetworking/model/User.java new file mode 100644 index 0000000..4337a8f --- /dev/null +++ b/android-networking/src/androidTest/java/com/androidnetworking/model/User.java @@ -0,0 +1,31 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.model; + +/** + * Created by amitshekhar on 10/04/17. + */ + +public class User { + + public String firstName; + public String lastName; + +} diff --git a/android-networking/src/main/AndroidManifest.xml b/android-networking/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3986b22 --- /dev/null +++ b/android-networking/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + diff --git a/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java b/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java new file mode 100644 index 0000000..290bfc6 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking; + +import android.content.Context; +import android.graphics.BitmapFactory; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ConnectionClassManager; +import com.androidnetworking.common.ConnectionQuality; +import com.androidnetworking.interceptors.HttpLoggingInterceptor.Level; +import com.androidnetworking.core.Core; +import com.androidnetworking.interfaces.ConnectionQualityChangeListener; +import com.androidnetworking.interfaces.Parser; +import com.androidnetworking.internal.ANImageLoader; +import com.androidnetworking.internal.ANRequestQueue; +import com.androidnetworking.internal.InternalNetworking; +import com.androidnetworking.utils.ParseUtil; +import com.androidnetworking.utils.Utils; + +import okhttp3.OkHttpClient; + +/** + * Created by amitshekhar on 24/03/16. + */ + +/** + * AndroidNetworking entry point. + * You must initialize this class before use. The simplest way is to just do + * {#code AndroidNetworking.initialize(context)}. + */ +@SuppressWarnings("unused") +public class AndroidNetworking { + + /** + * private constructor to prevent instantiation of this class + */ + private AndroidNetworking() { + } + + /** + * Initializes AndroidNetworking with the default config. + * + * @param context The context + */ + public static void initialize(Context context) { + InternalNetworking.setClientWithCache(context.getApplicationContext()); + ANRequestQueue.initialize(); + ANImageLoader.initialize(); + } + + /** + * Initializes AndroidNetworking with the specified config. + * + * @param context The context + * @param okHttpClient The okHttpClient + */ + public static void initialize(Context context, OkHttpClient okHttpClient) { + if (okHttpClient != null && okHttpClient.cache() == null) { + okHttpClient = okHttpClient + .newBuilder() + .cache(Utils.getCache(context.getApplicationContext(), + ANConstants.MAX_CACHE_SIZE, ANConstants.CACHE_DIR_NAME)) + .build(); + } + InternalNetworking.setClient(okHttpClient); + ANRequestQueue.initialize(); + ANImageLoader.initialize(); + } + + /** + * Method to set decodeOptions + * + * @param decodeOptions The decode config for Bitmaps + */ + public static void setBitmapDecodeOptions(BitmapFactory.Options decodeOptions) { + if (decodeOptions != null) { + ANImageLoader.getInstance().setBitmapDecodeOptions(decodeOptions); + } + } + + /** + * Method to set connectionQualityChangeListener + * + * @param connectionChangeListener The connectionQualityChangeListener + */ + public static void setConnectionQualityChangeListener(ConnectionQualityChangeListener connectionChangeListener) { + ConnectionClassManager.getInstance().setListener(connectionChangeListener); + } + + /** + * Method to set connectionQualityChangeListener + */ + public static void removeConnectionQualityChangeListener() { + ConnectionClassManager.getInstance().removeListener(); + } + + /** + * Method to make GET request + * + * @param url The url on which request is to be made + * @return The GetRequestBuilder + */ + public static ANRequest.GetRequestBuilder get(String url) { + return new ANRequest.GetRequestBuilder(url); + } + + /** + * Method to make HEAD request + * + * @param url The url on which request is to be made + * @return The HeadRequestBuilder + */ + public static ANRequest.HeadRequestBuilder head(String url) { + return new ANRequest.HeadRequestBuilder(url); + } + + /** + * Method to make POST request + * + * @param url The url on which request is to be made + * @return The PostRequestBuilder + */ + public static ANRequest.PostRequestBuilder post(String url) { + return new ANRequest.PostRequestBuilder(url); + } + + /** + * Method to make PUT request + * + * @param url The url on which request is to be made + * @return The PutRequestBuilder + */ + public static ANRequest.PutRequestBuilder put(String url) { + return new ANRequest.PutRequestBuilder(url); + } + + /** + * Method to make DELETE request + * + * @param url The url on which request is to be made + * @return The DeleteRequestBuilder + */ + public static ANRequest.DeleteRequestBuilder delete(String url) { + return new ANRequest.DeleteRequestBuilder(url); + } + + /** + * Method to make PATCH request + * + * @param url The url on which request is to be made + * @return The PatchRequestBuilder + */ + public static ANRequest.PatchRequestBuilder patch(String url) { + return new ANRequest.PatchRequestBuilder(url); + } + + /** + * Method to make download request + * + * @param url The url on which request is to be made + * @param dirPath The directory path on which file is to be saved + * @param fileName The file name with which file is to be saved + * @return The DownloadBuilder + */ + public static ANRequest.DownloadBuilder download(String url, String dirPath, String fileName) { + return new ANRequest.DownloadBuilder(url, dirPath, fileName); + } + + /** + * Method to make upload request + * + * @param url The url on which request is to be made + * @return The MultiPartBuilder + */ + public static ANRequest.MultiPartBuilder upload(String url) { + return new ANRequest.MultiPartBuilder(url); + } + + /** + * Method to cancel requests with the given tag + * + * @param tag The tag with which requests are to be cancelled + */ + public static void cancel(Object tag) { + ANRequestQueue.getInstance().cancelRequestWithGivenTag(tag, false); + } + + /** + * Method to force cancel requests with the given tag + * + * @param tag The tag with which requests are to be cancelled + */ + public static void forceCancel(Object tag) { + ANRequestQueue.getInstance().cancelRequestWithGivenTag(tag, true); + } + + /** + * Method to cancel all given request + */ + public static void cancelAll() { + ANRequestQueue.getInstance().cancelAll(false); + } + + /** + * Method to force cancel all given request + */ + public static void forceCancelAll() { + ANRequestQueue.getInstance().cancelAll(true); + } + + /** + * Method to enable logging + */ + public static void enableLogging() { + enableLogging(Level.BASIC); + } + + /** + * Method to enable logging with tag + * + * @param level The level for logging + */ + public static void enableLogging(Level level) { + InternalNetworking.enableLogging(level); + } + + /** + * Method to evict a bitmap with given key from LruCache + * + * @param key The key of the bitmap + */ + public static void evictBitmap(String key) { + final ANImageLoader.ImageCache imageCache = ANImageLoader.getInstance().getImageCache(); + if (imageCache != null && key != null) { + imageCache.evictBitmap(key); + } + } + + /** + * Method to clear LruCache + */ + public static void evictAllBitmap() { + final ANImageLoader.ImageCache imageCache = ANImageLoader.getInstance().getImageCache(); + if (imageCache != null) { + imageCache.evictAllBitmap(); + } + } + + /** + * Method to set userAgent globally + * + * @param userAgent The userAgent + */ + public static void setUserAgent(String userAgent) { + InternalNetworking.setUserAgent(userAgent); + } + + /** + * Method to get currentBandwidth + * + * @return currentBandwidth + */ + public static int getCurrentBandwidth() { + return ConnectionClassManager.getInstance().getCurrentBandwidth(); + } + + /** + * Method to get currentConnectionQuality + * + * @return currentConnectionQuality + */ + public static ConnectionQuality getCurrentConnectionQuality() { + return ConnectionClassManager.getInstance().getCurrentConnectionQuality(); + } + + /** + * Method to set ParserFactory + * + * @param parserFactory The ParserFactory + */ + public static void setParserFactory(Parser.Factory parserFactory) { + ParseUtil.setParserFactory(parserFactory); + } + + /** + * Shuts AndroidNetworking down + */ + public static void shutDown() { + Core.shutDown(); + evictAllBitmap(); + ConnectionClassManager.getInstance().removeListener(); + ConnectionClassManager.shutDown(); + ParseUtil.shutDown(); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java b/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java new file mode 100644 index 0000000..a47d74f --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.cache; + +import android.graphics.Bitmap; + +import com.androidnetworking.internal.ANImageLoader; + +/** + * Created by amitshekhar on 24/03/16. + */ +public class LruBitmapCache extends LruCache + implements ANImageLoader.ImageCache { + + public LruBitmapCache(int maxSize) { + super(maxSize); + } + + @Override + protected int sizeOf(String key, Bitmap value) { + return value.getRowBytes() * value.getHeight(); + } + + @Override + public Bitmap getBitmap(String key) { + return get(key); + } + + @Override + public void evictBitmap(String key) { + remove(key); + } + + @Override + public void evictAllBitmap() { + evictAll(); + } + + @Override + public void putBitmap(String url, Bitmap bitmap) { + put(url, bitmap); + } + +} diff --git a/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java b/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java new file mode 100644 index 0000000..509d295 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.cache; + +import android.annotation.SuppressLint; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Created by amitshekhar on 28/05/16. + */ +public class LruCache { + private final LinkedHashMap map; + + private int size; + private int maxSize; + + private int putCount; + private int createCount; + private int evictionCount; + private int hitCount; + private int missCount; + + public LruCache(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + this.maxSize = maxSize; + this.map = new LinkedHashMap(0, 0.75f, true); + } + + public void resize(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + + synchronized (this) { + this.maxSize = maxSize; + } + trimToSize(maxSize); + } + + public final V get(K key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + V mapValue; + synchronized (this) { + mapValue = map.get(key); + if (mapValue != null) { + hitCount++; + return mapValue; + } + missCount++; + } + + V createdValue = create(key); + if (createdValue == null) { + return null; + } + + synchronized (this) { + createCount++; + mapValue = map.put(key, createdValue); + + if (mapValue != null) { + // There was a conflict so undo that last put + map.put(key, mapValue); + } else { + size += safeSizeOf(key, createdValue); + } + } + + if (mapValue != null) { + entryRemoved(false, key, createdValue, mapValue); + return mapValue; + } else { + trimToSize(maxSize); + return createdValue; + } + } + + public final V put(K key, V value) { + if (key == null || value == null) { + throw new NullPointerException("key == null || value == null"); + } + + V previous; + synchronized (this) { + putCount++; + size += safeSizeOf(key, value); + previous = map.put(key, value); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, value); + } + + trimToSize(maxSize); + return previous; + } + + public void trimToSize(int maxSize) { + while (true) { + K key; + V value; + synchronized (this) { + if (size < 0 || (map.isEmpty() && size != 0)) { + throw new IllegalStateException(getClass().getName() + + ".sizeOf() is reporting inconsistent results!"); + } + + if (size <= maxSize || map.isEmpty()) { + break; + } + + Map.Entry toEvict = map.entrySet().iterator().next(); + key = toEvict.getKey(); + value = toEvict.getValue(); + map.remove(key); + size -= safeSizeOf(key, value); + evictionCount++; + } + + entryRemoved(true, key, value, null); + } + } + + public final V remove(K key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + V previous; + synchronized (this) { + previous = map.remove(key); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, null); + } + + return previous; + } + + protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) { + } + + protected V create(K key) { + return null; + } + + private int safeSizeOf(K key, V value) { + int result = sizeOf(key, value); + if (result < 0) { + throw new IllegalStateException("Negative size: " + key + "=" + value); + } + return result; + } + + protected int sizeOf(K key, V value) { + return 1; + } + + public final void evictAll() { + trimToSize(-1); + } + + public synchronized final int size() { + return size; + } + + public synchronized final int maxSize() { + return maxSize; + } + + public synchronized final int hitCount() { + return hitCount; + } + + public synchronized final int missCount() { + return missCount; + } + + public synchronized final int createCount() { + return createCount; + } + + public synchronized final int putCount() { + return putCount; + } + + public synchronized final int evictionCount() { + return evictionCount; + } + + public synchronized final Map snapshot() { + return new LinkedHashMap(map); + } + + @SuppressLint("DefaultLocale") + @Override + public synchronized final String toString() { + int accesses = hitCount + missCount; + int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0; + return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", + maxSize, hitCount, missCount, hitPercent); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java b/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java new file mode 100644 index 0000000..cafda96 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +/** + * Created by amitshekhar on 29/03/16. + */ +public final class ANConstants { + public static final int MAX_CACHE_SIZE = 10 * 1024 * 1024; + public static final int UPDATE = 0x01; + public static final String CACHE_DIR_NAME = "cache_an"; + public static final String CONNECTION_ERROR = "connectionError"; + public static final String RESPONSE_FROM_SERVER_ERROR = "responseFromServerError"; + public static final String REQUEST_CANCELLED_ERROR = "requestCancelledError"; + public static final String PARSE_ERROR = "parseError"; + public static final String NETWORK_ON_MAIN_THREAD_ERROR = "networkOnMainThreadError"; + public static final String PREFETCH = "prefetch"; + public static final String FAST_ANDROID_NETWORKING = "FastAndroidNetworking"; + public static final String USER_AGENT = "User-Agent"; + public static final String SUCCESS = "success"; +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java b/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java new file mode 100644 index 0000000..9a18351 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java @@ -0,0 +1,1712 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.widget.ImageView; + +import com.androidnetworking.core.Core; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.AnalyticsListener; +import com.androidnetworking.interfaces.BitmapRequestListener; +import com.androidnetworking.interfaces.DownloadListener; +import com.androidnetworking.interfaces.DownloadProgressListener; +import com.androidnetworking.interfaces.JSONArrayRequestListener; +import com.androidnetworking.interfaces.JSONObjectRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndBitmapRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONArrayRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndJSONObjectRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndParsedRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseAndStringRequestListener; +import com.androidnetworking.interfaces.OkHttpResponseListener; +import com.androidnetworking.interfaces.ParsedRequestListener; +import com.androidnetworking.interfaces.StringRequestListener; +import com.androidnetworking.interfaces.UploadProgressListener; +import com.androidnetworking.internal.ANRequestQueue; +import com.androidnetworking.internal.SynchronousCall; +import com.androidnetworking.utils.ParseUtil; +import com.androidnetworking.utils.Utils; +import com.google.gson.internal.$Gson$Types; +import com.google.gson.reflect.TypeToken; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import okhttp3.CacheControl; +import okhttp3.Call; +import okhttp3.FormBody; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.Response; +import okio.Okio; + +/** + * Created by amitshekhar on 26/03/16. + */ +@SuppressWarnings({"unchecked", "unused"}) +public class ANRequest { + + private final static String TAG = ANRequest.class.getSimpleName(); + + private int mMethod; + private Priority mPriority; + private int mRequestType; + private String mUrl; + private int sequenceNumber; + private Object mTag; + private ResponseType mResponseType; + private HashMap mHeadersMap = new HashMap<>(); + private HashMap mBodyParameterMap = new HashMap<>(); + private HashMap mUrlEncodedFormBodyParameterMap = new HashMap<>(); + private HashMap mMultiPartParameterMap = new HashMap<>(); + private HashMap mQueryParameterMap = new HashMap<>(); + private HashMap mPathParameterMap = new HashMap<>(); + private HashMap mMultiPartFileMap = new HashMap<>(); + private String mDirPath; + private String mFileName; + private String mApplicationJsonString = null; + private String mStringBody = null; + private byte[] mByte = null; + private File mFile = null; + private static final MediaType JSON_MEDIA_TYPE = + MediaType.parse("application/json; charset=utf-8"); + private static final MediaType MEDIA_TYPE_MARKDOWN = + MediaType.parse("text/x-markdown; charset=utf-8"); + private MediaType customMediaType = null; + private static final Object sDecodeLock = new Object(); + + private Future future; + private Call call; + private int mProgress; + private boolean isCancelled; + private boolean isDelivered; + private int mPercentageThresholdForCancelling = 0; + private JSONArrayRequestListener mJSONArrayRequestListener; + private JSONObjectRequestListener mJSONObjectRequestListener; + private StringRequestListener mStringRequestListener; + private OkHttpResponseListener mOkHttpResponseListener; + private BitmapRequestListener mBitmapRequestListener; + private ParsedRequestListener mParsedRequestListener; + private OkHttpResponseAndJSONObjectRequestListener mOkHttpResponseAndJSONObjectRequestListener; + private OkHttpResponseAndJSONArrayRequestListener mOkHttpResponseAndJSONArrayRequestListener; + private OkHttpResponseAndStringRequestListener mOkHttpResponseAndStringRequestListener; + private OkHttpResponseAndBitmapRequestListener mOkHttpResponseAndBitmapRequestListener; + private OkHttpResponseAndParsedRequestListener mOkHttpResponseAndParsedRequestListener; + private DownloadProgressListener mDownloadProgressListener; + private UploadProgressListener mUploadProgressListener; + private DownloadListener mDownloadListener; + private AnalyticsListener mAnalyticsListener; + + private Bitmap.Config mDecodeConfig; + private int mMaxWidth; + private int mMaxHeight; + private ImageView.ScaleType mScaleType; + private CacheControl mCacheControl = null; + private Executor mExecutor = null; + private OkHttpClient mOkHttpClient = null; + private String mUserAgent = null; + private Type mType = null; + + public ANRequest(GetRequestBuilder builder) { + this.mRequestType = RequestType.SIMPLE; + this.mMethod = builder.mMethod; + this.mPriority = builder.mPriority; + this.mUrl = builder.mUrl; + this.mTag = builder.mTag; + this.mHeadersMap = builder.mHeadersMap; + this.mDecodeConfig = builder.mDecodeConfig; + this.mMaxHeight = builder.mMaxHeight; + this.mMaxWidth = builder.mMaxWidth; + this.mScaleType = builder.mScaleType; + this.mQueryParameterMap = builder.mQueryParameterMap; + this.mPathParameterMap = builder.mPathParameterMap; + this.mCacheControl = builder.mCacheControl; + this.mExecutor = builder.mExecutor; + this.mOkHttpClient = builder.mOkHttpClient; + this.mUserAgent = builder.mUserAgent; + } + + public ANRequest(PostRequestBuilder builder) { + this.mRequestType = RequestType.SIMPLE; + this.mMethod = builder.mMethod; + this.mPriority = builder.mPriority; + this.mUrl = builder.mUrl; + this.mTag = builder.mTag; + this.mHeadersMap = builder.mHeadersMap; + this.mBodyParameterMap = builder.mBodyParameterMap; + this.mUrlEncodedFormBodyParameterMap = builder.mUrlEncodedFormBodyParameterMap; + this.mQueryParameterMap = builder.mQueryParameterMap; + this.mPathParameterMap = builder.mPathParameterMap; + this.mApplicationJsonString = builder.mApplicationJsonString; + this.mStringBody = builder.mStringBody; + this.mFile = builder.mFile; + this.mByte = builder.mByte; + this.mCacheControl = builder.mCacheControl; + this.mExecutor = builder.mExecutor; + this.mOkHttpClient = builder.mOkHttpClient; + this.mUserAgent = builder.mUserAgent; + if (builder.mCustomContentType != null) { + this.customMediaType = MediaType.parse(builder.mCustomContentType); + } + } + + public ANRequest(DownloadBuilder builder) { + this.mRequestType = RequestType.DOWNLOAD; + this.mMethod = Method.GET; + this.mPriority = builder.mPriority; + this.mUrl = builder.mUrl; + this.mTag = builder.mTag; + this.mDirPath = builder.mDirPath; + this.mFileName = builder.mFileName; + this.mHeadersMap = builder.mHeadersMap; + this.mQueryParameterMap = builder.mQueryParameterMap; + this.mPathParameterMap = builder.mPathParameterMap; + this.mCacheControl = builder.mCacheControl; + this.mPercentageThresholdForCancelling = builder.mPercentageThresholdForCancelling; + this.mExecutor = builder.mExecutor; + this.mOkHttpClient = builder.mOkHttpClient; + this.mUserAgent = builder.mUserAgent; + } + + public ANRequest(MultiPartBuilder builder) { + this.mRequestType = RequestType.MULTIPART; + this.mMethod = Method.POST; + this.mPriority = builder.mPriority; + this.mUrl = builder.mUrl; + this.mTag = builder.mTag; + this.mHeadersMap = builder.mHeadersMap; + this.mQueryParameterMap = builder.mQueryParameterMap; + this.mPathParameterMap = builder.mPathParameterMap; + this.mMultiPartParameterMap = builder.mMultiPartParameterMap; + this.mMultiPartFileMap = builder.mMultiPartFileMap; + this.mCacheControl = builder.mCacheControl; + this.mPercentageThresholdForCancelling = builder.mPercentageThresholdForCancelling; + this.mExecutor = builder.mExecutor; + this.mOkHttpClient = builder.mOkHttpClient; + this.mUserAgent = builder.mUserAgent; + if (builder.mCustomContentType != null) { + this.customMediaType = MediaType.parse(builder.mCustomContentType); + } + } + + public void getAsJSONObject(JSONObjectRequestListener requestListener) { + this.mResponseType = ResponseType.JSON_OBJECT; + this.mJSONObjectRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsJSONArray(JSONArrayRequestListener requestListener) { + this.mResponseType = ResponseType.JSON_ARRAY; + this.mJSONArrayRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsString(StringRequestListener requestListener) { + this.mResponseType = ResponseType.STRING; + this.mStringRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponse(OkHttpResponseListener requestListener) { + this.mResponseType = ResponseType.OK_HTTP_RESPONSE; + this.mOkHttpResponseListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsBitmap(BitmapRequestListener requestListener) { + this.mResponseType = ResponseType.BITMAP; + this.mBitmapRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsParsed(TypeToken typeToken, ParsedRequestListener parsedRequestListener) { + this.mType = typeToken.getType(); + this.mResponseType = ResponseType.PARSED; + this.mParsedRequestListener = parsedRequestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsObject(Class objectClass, ParsedRequestListener parsedRequestListener) { + this.mType = objectClass; + this.mResponseType = ResponseType.PARSED; + this.mParsedRequestListener = parsedRequestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsObjectList(Class objectClass, ParsedRequestListener parsedRequestListener) { + this.mType = $Gson$Types.newParameterizedTypeWithOwner(null, List.class, objectClass); + this.mResponseType = ResponseType.PARSED; + this.mParsedRequestListener = parsedRequestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponseAndJSONObject(OkHttpResponseAndJSONObjectRequestListener requestListener) { + this.mResponseType = ResponseType.JSON_OBJECT; + this.mOkHttpResponseAndJSONObjectRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponseAndJSONArray(OkHttpResponseAndJSONArrayRequestListener requestListener) { + this.mResponseType = ResponseType.JSON_ARRAY; + this.mOkHttpResponseAndJSONArrayRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponseAndString(OkHttpResponseAndStringRequestListener requestListener) { + this.mResponseType = ResponseType.STRING; + this.mOkHttpResponseAndStringRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + + public void getAsOkHttpResponseAndBitmap(OkHttpResponseAndBitmapRequestListener requestListener) { + this.mResponseType = ResponseType.BITMAP; + this.mOkHttpResponseAndBitmapRequestListener = requestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponseAndParsed(TypeToken typeToken, OkHttpResponseAndParsedRequestListener parsedRequestListener) { + this.mType = typeToken.getType(); + this.mResponseType = ResponseType.PARSED; + this.mOkHttpResponseAndParsedRequestListener = parsedRequestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponseAndObject(Class objectClass, OkHttpResponseAndParsedRequestListener parsedRequestListener) { + this.mType = objectClass; + this.mResponseType = ResponseType.PARSED; + this.mOkHttpResponseAndParsedRequestListener = parsedRequestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void getAsOkHttpResponseAndObjectList(Class objectClass, OkHttpResponseAndParsedRequestListener parsedRequestListener) { + this.mType = $Gson$Types.newParameterizedTypeWithOwner(null, List.class, objectClass); + this.mResponseType = ResponseType.PARSED; + this.mOkHttpResponseAndParsedRequestListener = parsedRequestListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void startDownload(DownloadListener downloadListener) { + this.mDownloadListener = downloadListener; + ANRequestQueue.getInstance().addRequest(this); + } + + public void prefetch() { + this.mResponseType = ResponseType.PREFETCH; + ANRequestQueue.getInstance().addRequest(this); + } + + public ANResponse executeForJSONObject() { + this.mResponseType = ResponseType.JSON_OBJECT; + return SynchronousCall.execute(this); + } + + public ANResponse executeForJSONArray() { + this.mResponseType = ResponseType.JSON_ARRAY; + return SynchronousCall.execute(this); + } + + public ANResponse executeForString() { + this.mResponseType = ResponseType.STRING; + return SynchronousCall.execute(this); + } + + public ANResponse executeForOkHttpResponse() { + this.mResponseType = ResponseType.OK_HTTP_RESPONSE; + return SynchronousCall.execute(this); + } + + public ANResponse executeForBitmap() { + this.mResponseType = ResponseType.BITMAP; + return SynchronousCall.execute(this); + } + + public ANResponse executeForParsed(TypeToken typeToken) { + this.mType = typeToken.getType(); + this.mResponseType = ResponseType.PARSED; + return SynchronousCall.execute(this); + } + + public ANResponse executeForObject(Class objectClass) { + this.mType = objectClass; + this.mResponseType = ResponseType.PARSED; + return SynchronousCall.execute(this); + } + + public ANResponse executeForObjectList(Class objectClass) { + this.mType = $Gson$Types.newParameterizedTypeWithOwner(null, List.class, objectClass); + this.mResponseType = ResponseType.PARSED; + return SynchronousCall.execute(this); + } + + public ANResponse executeForDownload() { + return SynchronousCall.execute(this); + } + + public T setDownloadProgressListener(DownloadProgressListener downloadProgressListener) { + this.mDownloadProgressListener = downloadProgressListener; + return (T) this; + } + + public T setUploadProgressListener(UploadProgressListener uploadProgressListener) { + this.mUploadProgressListener = uploadProgressListener; + return (T) this; + } + + public T setAnalyticsListener(AnalyticsListener analyticsListener) { + this.mAnalyticsListener = analyticsListener; + return (T) this; + } + + public AnalyticsListener getAnalyticsListener() { + return mAnalyticsListener; + } + + public int getMethod() { + return mMethod; + } + + public Priority getPriority() { + return mPriority; + } + + public String getUrl() { + String tempUrl = mUrl; + for (HashMap.Entry entry : mPathParameterMap.entrySet()) { + tempUrl = tempUrl.replace("{" + entry.getKey() + "}", String.valueOf(entry.getValue())); + } + HttpUrl.Builder urlBuilder = HttpUrl.parse(tempUrl).newBuilder(); + for (HashMap.Entry entry : mQueryParameterMap.entrySet()) { + urlBuilder.addQueryParameter(entry.getKey(), entry.getValue()); + } + return urlBuilder.build().toString(); + } + + public int getSequenceNumber() { + return sequenceNumber; + } + + public void setSequenceNumber(int sequenceNumber) { + this.sequenceNumber = sequenceNumber; + } + + public void setProgress(int progress) { + this.mProgress = progress; + } + + public void setResponseAs(ResponseType responseType) { + this.mResponseType = responseType; + } + + public ResponseType getResponseAs() { + return mResponseType; + } + + public Object getTag() { + return mTag; + } + + public int getRequestType() { + return mRequestType; + } + + public OkHttpClient getOkHttpClient() { + return mOkHttpClient; + } + + public void setUserAgent(String userAgent) { + this.mUserAgent = userAgent; + } + + public String getUserAgent() { + return mUserAgent; + } + + public Type getType() { + return mType; + } + + public void setType(Type type) { + this.mType = type; + } + + public DownloadProgressListener getDownloadProgressListener() { + return new DownloadProgressListener() { + @Override + public void onProgress(final long bytesDownloaded, final long totalBytes) { + if (mDownloadProgressListener != null && !isCancelled) { + mDownloadProgressListener.onProgress(bytesDownloaded, totalBytes); + } + } + }; + } + + public void updateDownloadCompletion() { + isDelivered = true; + if (mDownloadListener != null) { + if (!isCancelled) { + if (mExecutor != null) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + if (mDownloadListener != null) { + mDownloadListener.onDownloadComplete(); + } + finish(); + } + }); + } else { + Core.getInstance().getExecutorSupplier().forMainThreadTasks().execute(new Runnable() { + @Override + public void run() { + if (mDownloadListener != null) { + mDownloadListener.onDownloadComplete(); + } + finish(); + } + }); + } + } else { + deliverError(new ANError()); + finish(); + } + } else { + finish(); + } + } + + public UploadProgressListener getUploadProgressListener() { + return new UploadProgressListener() { + @Override + public void onProgress(final long bytesUploaded, final long totalBytes) { + mProgress = (int) ((bytesUploaded * 100) / totalBytes); + if (mUploadProgressListener != null && !isCancelled) { + mUploadProgressListener.onProgress(bytesUploaded, totalBytes); + } + } + }; + } + + public String getDirPath() { + return mDirPath; + } + + public String getFileName() { + return mFileName; + } + + public CacheControl getCacheControl() { + return mCacheControl; + } + + public ImageView.ScaleType getScaleType() { + return mScaleType; + } + + public void cancel(boolean forceCancel) { + try { + if (forceCancel || mPercentageThresholdForCancelling == 0 + || mProgress < mPercentageThresholdForCancelling) { + isCancelled = true; + if (call != null) { + call.cancel(); + } + if (future != null) { + future.cancel(true); + } + if (!isDelivered) { + deliverError(new ANError()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public boolean isCanceled() { + return isCancelled; + } + + public Call getCall() { + return call; + } + + public void setCall(Call call) { + this.call = call; + } + + public Future getFuture() { + return future; + } + + public void setFuture(Future future) { + this.future = future; + } + + public void destroy() { + mJSONArrayRequestListener = null; + mJSONArrayRequestListener = null; + mStringRequestListener = null; + mBitmapRequestListener = null; + mParsedRequestListener = null; + mDownloadProgressListener = null; + mUploadProgressListener = null; + mDownloadListener = null; + mAnalyticsListener = null; + } + + public void finish() { + destroy(); + ANRequestQueue.getInstance().finish(this); + } + + public ANResponse parseResponse(Response response) { + switch (mResponseType) { + case JSON_ARRAY: + try { + JSONArray json = new JSONArray(Okio.buffer(response.body().source()).readUtf8()); + return ANResponse.success(json); + } catch (Exception e) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(e))); + } + case JSON_OBJECT: + try { + JSONObject json = new JSONObject(Okio.buffer(response.body() + .source()).readUtf8()); + return ANResponse.success(json); + } catch (Exception e) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(e))); + } + case STRING: + try { + return ANResponse.success(Okio.buffer(response + .body().source()).readUtf8()); + } catch (Exception e) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(e))); + } + case BITMAP: + synchronized (sDecodeLock) { + try { + return Utils.decodeBitmap(response, mMaxWidth, mMaxHeight, + mDecodeConfig, mScaleType); + } catch (Exception e) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(e))); + } + } + case PARSED: + try { + return ANResponse.success(ParseUtil.getParserFactory() + .responseBodyParser(mType).convert(response.body())); + } catch (Exception e) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(e))); + } + case PREFETCH: + try { + Okio.buffer(response.body().source()).skip(Long.MAX_VALUE); + return ANResponse.success(ANConstants.PREFETCH); + } catch (Exception e) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(e))); + } + } + return null; + } + + public ANError parseNetworkError(ANError anError) { + try { + if (anError.getResponse() != null && anError.getResponse().body() != null + && anError.getResponse().body().source() != null) { + anError.setErrorBody(Okio.buffer(anError + .getResponse().body().source()).readUtf8()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return anError; + } + + public synchronized void deliverError(ANError anError) { + try { + if (!isDelivered) { + if (isCancelled) { + anError.setCancellationMessageInError(); + anError.setErrorCode(0); + } + deliverErrorResponse(anError); + } + isDelivered = true; + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public void deliverResponse(final ANResponse response) { + try { + isDelivered = true; + if (!isCancelled) { + if (mExecutor != null) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + deliverSuccessResponse(response); + } + }); + } else { + Core.getInstance().getExecutorSupplier().forMainThreadTasks().execute(new Runnable() { + public void run() { + deliverSuccessResponse(response); + } + }); + } + } else { + ANError anError = new ANError(); + anError.setCancellationMessageInError(); + anError.setErrorCode(0); + deliverErrorResponse(anError); + finish(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void deliverSuccessResponse(ANResponse response) { + if (mJSONObjectRequestListener != null) { + mJSONObjectRequestListener.onResponse((JSONObject) response.getResult()); + } else if (mJSONArrayRequestListener != null) { + mJSONArrayRequestListener.onResponse((JSONArray) response.getResult()); + } else if (mStringRequestListener != null) { + mStringRequestListener.onResponse((String) response.getResult()); + } else if (mBitmapRequestListener != null) { + mBitmapRequestListener.onResponse((Bitmap) response.getResult()); + } else if (mParsedRequestListener != null) { + mParsedRequestListener.onResponse(response.getResult()); + } else if (mOkHttpResponseAndJSONObjectRequestListener != null) { + mOkHttpResponseAndJSONObjectRequestListener.onResponse(response.getOkHttpResponse(), (JSONObject) response.getResult()); + } else if (mOkHttpResponseAndJSONArrayRequestListener != null) { + mOkHttpResponseAndJSONArrayRequestListener.onResponse(response.getOkHttpResponse(), (JSONArray) response.getResult()); + } else if (mOkHttpResponseAndStringRequestListener != null) { + mOkHttpResponseAndStringRequestListener.onResponse(response.getOkHttpResponse(), (String) response.getResult()); + } else if (mOkHttpResponseAndBitmapRequestListener != null) { + mOkHttpResponseAndBitmapRequestListener.onResponse(response.getOkHttpResponse(), (Bitmap) response.getResult()); + } else if (mOkHttpResponseAndParsedRequestListener != null) { + mOkHttpResponseAndParsedRequestListener.onResponse(response.getOkHttpResponse(), response.getResult()); + } + finish(); + } + + private void deliverErrorResponse(ANError anError) { + if (mJSONObjectRequestListener != null) { + mJSONObjectRequestListener.onError(anError); + } else if (mJSONArrayRequestListener != null) { + mJSONArrayRequestListener.onError(anError); + } else if (mStringRequestListener != null) { + mStringRequestListener.onError(anError); + } else if (mBitmapRequestListener != null) { + mBitmapRequestListener.onError(anError); + } else if (mParsedRequestListener != null) { + mParsedRequestListener.onError(anError); + } else if (mOkHttpResponseListener != null) { + mOkHttpResponseListener.onError(anError); + } else if (mOkHttpResponseAndJSONObjectRequestListener != null) { + mOkHttpResponseAndJSONObjectRequestListener.onError(anError); + } else if (mOkHttpResponseAndJSONArrayRequestListener != null) { + mOkHttpResponseAndJSONArrayRequestListener.onError(anError); + } else if (mOkHttpResponseAndStringRequestListener != null) { + mOkHttpResponseAndStringRequestListener.onError(anError); + } else if (mOkHttpResponseAndBitmapRequestListener != null) { + mOkHttpResponseAndBitmapRequestListener.onError(anError); + } else if (mOkHttpResponseAndParsedRequestListener != null) { + mOkHttpResponseAndParsedRequestListener.onError(anError); + } else if (mDownloadListener != null) { + mDownloadListener.onError(anError); + } + } + + public void deliverOkHttpResponse(final Response response) { + try { + isDelivered = true; + if (!isCancelled) { + if (mExecutor != null) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + if (mOkHttpResponseListener != null) { + mOkHttpResponseListener.onResponse(response); + } + finish(); + } + }); + } else { + Core.getInstance().getExecutorSupplier().forMainThreadTasks().execute(new Runnable() { + public void run() { + if (mOkHttpResponseListener != null) { + mOkHttpResponseListener.onResponse(response); + } + finish(); + } + }); + } + } else { + ANError anError = new ANError(); + anError.setCancellationMessageInError(); + anError.setErrorCode(0); + if (mOkHttpResponseListener != null) { + mOkHttpResponseListener.onError(anError); + } + finish(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public RequestBody getRequestBody() { + if (mApplicationJsonString != null) { + if (customMediaType != null) { + return RequestBody.create(customMediaType, mApplicationJsonString); + } + return RequestBody.create(JSON_MEDIA_TYPE, mApplicationJsonString); + } else if (mStringBody != null) { + if (customMediaType != null) { + return RequestBody.create(customMediaType, mStringBody); + } + return RequestBody.create(MEDIA_TYPE_MARKDOWN, mStringBody); + } else if (mFile != null) { + if (customMediaType != null) { + return RequestBody.create(customMediaType, mFile); + } + return RequestBody.create(MEDIA_TYPE_MARKDOWN, mFile); + } else if (mByte != null) { + if (customMediaType != null) { + return RequestBody.create(customMediaType, mByte); + } + return RequestBody.create(MEDIA_TYPE_MARKDOWN, mByte); + } else { + FormBody.Builder builder = new FormBody.Builder(); + try { + for (HashMap.Entry entry : mBodyParameterMap.entrySet()) { + builder.add(entry.getKey(), entry.getValue()); + } + for (HashMap.Entry entry : mUrlEncodedFormBodyParameterMap.entrySet()) { + builder.addEncoded(entry.getKey(), entry.getValue()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return builder.build(); + } + } + + public RequestBody getMultiPartRequestBody() { + MultipartBody.Builder builder = new MultipartBody + .Builder() + .setType((customMediaType == null) ? MultipartBody.FORM : customMediaType); + try { + for (HashMap.Entry entry : mMultiPartParameterMap.entrySet()) { + builder.addPart(Headers.of("Content-Disposition", + "form-data; name=\"" + entry.getKey() + "\""), + RequestBody.create(null, entry.getValue())); + } + for (HashMap.Entry entry : mMultiPartFileMap.entrySet()) { + String fileName = entry.getValue().getName(); + RequestBody fileBody = RequestBody.create(MediaType.parse(Utils.getMimeType(fileName)), + entry.getValue()); + builder.addPart(Headers.of("Content-Disposition", + "form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\""), + fileBody); + } + } catch (Exception e) { + e.printStackTrace(); + } + return builder.build(); + } + + public Headers getHeaders() { + Headers.Builder builder = new Headers.Builder(); + try { + for (HashMap.Entry entry : mHeadersMap.entrySet()) { + builder.add(entry.getKey(), entry.getValue()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return builder.build(); + } + + public static class HeadRequestBuilder extends GetRequestBuilder { + + public HeadRequestBuilder(String url) { + super(url, Method.HEAD); + } + } + + public static class GetRequestBuilder implements RequestBuilder { + private Priority mPriority = Priority.MEDIUM; + private int mMethod = Method.GET; + private String mUrl; + private Object mTag; + private Bitmap.Config mDecodeConfig; + private BitmapFactory.Options mBitmapOptions; + private int mMaxWidth; + private int mMaxHeight; + private ImageView.ScaleType mScaleType; + private HashMap mHeadersMap = new HashMap<>(); + private HashMap mQueryParameterMap = new HashMap<>(); + private HashMap mPathParameterMap = new HashMap<>(); + private CacheControl mCacheControl; + private Executor mExecutor; + private OkHttpClient mOkHttpClient; + private String mUserAgent; + + public GetRequestBuilder(String url) { + this.mUrl = url; + this.mMethod = Method.GET; + } + + public GetRequestBuilder(String url, int method) { + this.mUrl = url; + this.mMethod = method; + } + + @Override + public T setPriority(Priority priority) { + mPriority = priority; + return (T) this; + } + + @Override + public T setTag(Object tag) { + mTag = tag; + return (T) this; + } + + @Override + public T addQueryParameter(String key, String value) { + mQueryParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addQueryParameter(Map queryParameterMap) { + if (queryParameterMap != null) { + mQueryParameterMap.putAll(queryParameterMap); + } + return (T) this; + } + + @Override + public T addQueryParameter(Object object) { + if (object != null) { + mQueryParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addPathParameter(String key, String value) { + mPathParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addPathParameter(Map pathParameterMap) { + if (pathParameterMap != null) { + mPathParameterMap.putAll(pathParameterMap); + } + return (T) this; + } + + @Override + public T addPathParameter(Object object) { + if (object != null) { + mPathParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addHeaders(String key, String value) { + mHeadersMap.put(key, value); + return (T) this; + } + + @Override + public T addHeaders(Map headerMap) { + if (headerMap != null) { + mHeadersMap.putAll(headerMap); + } + return (T) this; + } + + @Override + public T addHeaders(Object object) { + if (object != null) { + mHeadersMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T doNotCacheResponse() { + mCacheControl = new CacheControl.Builder().noStore().build(); + return (T) this; + } + + @Override + public T getResponseOnlyIfCached() { + mCacheControl = CacheControl.FORCE_CACHE; + return (T) this; + } + + @Override + public T getResponseOnlyFromNetwork() { + mCacheControl = CacheControl.FORCE_NETWORK; + return (T) this; + } + + @Override + public T setMaxAgeCacheControl(int maxAge, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxAge(maxAge, timeUnit).build(); + return (T) this; + } + + @Override + public T setMaxStaleCacheControl(int maxStale, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxStale(maxStale, timeUnit).build(); + return (T) this; + } + + @Override + public T setExecutor(Executor executor) { + mExecutor = executor; + return (T) this; + } + + @Override + public T setOkHttpClient(OkHttpClient okHttpClient) { + mOkHttpClient = okHttpClient; + return (T) this; + } + + @Override + public T setUserAgent(String userAgent) { + mUserAgent = userAgent; + return (T) this; + } + + public T setBitmapConfig(Bitmap.Config bitmapConfig) { + mDecodeConfig = bitmapConfig; + return (T) this; + } + + public T setBitmapOptions(BitmapFactory.Options bitmapOptions) { + mBitmapOptions = bitmapOptions; + return (T) this; + } + + public T setBitmapMaxHeight(int maxHeight) { + mMaxHeight = maxHeight; + return (T) this; + } + + public T setBitmapMaxWidth(int maxWidth) { + mMaxWidth = maxWidth; + return (T) this; + } + + public T setImageScaleType(ImageView.ScaleType imageScaleType) { + mScaleType = imageScaleType; + return (T) this; + } + + public ANRequest build() { + return new ANRequest(this); + } + } + + public static class PutRequestBuilder extends PostRequestBuilder { + + public PutRequestBuilder(String url) { + super(url, Method.PUT); + } + } + + public static class DeleteRequestBuilder extends PostRequestBuilder { + + public DeleteRequestBuilder(String url) { + super(url, Method.DELETE); + } + } + + public static class PatchRequestBuilder extends PostRequestBuilder { + + public PatchRequestBuilder(String url) { + super(url, Method.PATCH); + } + } + + public static class PostRequestBuilder implements RequestBuilder { + + private Priority mPriority = Priority.MEDIUM; + private int mMethod = Method.POST; + private String mUrl; + private Object mTag; + private String mApplicationJsonString = null; + private String mStringBody = null; + private byte[] mByte = null; + private File mFile = null; + private HashMap mHeadersMap = new HashMap<>(); + private HashMap mBodyParameterMap = new HashMap<>(); + private HashMap mUrlEncodedFormBodyParameterMap = new HashMap<>(); + private HashMap mQueryParameterMap = new HashMap<>(); + private HashMap mPathParameterMap = new HashMap<>(); + private CacheControl mCacheControl; + private Executor mExecutor; + private OkHttpClient mOkHttpClient; + private String mUserAgent; + private String mCustomContentType; + + public PostRequestBuilder(String url) { + this.mUrl = url; + this.mMethod = Method.POST; + } + + public PostRequestBuilder(String url, int method) { + this.mUrl = url; + this.mMethod = method; + } + + @Override + public T setPriority(Priority priority) { + mPriority = priority; + return (T) this; + } + + @Override + public T setTag(Object tag) { + mTag = tag; + return (T) this; + } + + @Override + public T addQueryParameter(String key, String value) { + mQueryParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addQueryParameter(Map queryParameterMap) { + if (queryParameterMap != null) { + mQueryParameterMap.putAll(queryParameterMap); + } + return (T) this; + } + + @Override + public T addQueryParameter(Object object) { + if (object != null) { + mQueryParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addPathParameter(String key, String value) { + mPathParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addPathParameter(Map pathParameterMap) { + if (pathParameterMap != null) { + mPathParameterMap.putAll(pathParameterMap); + } + return (T) this; + } + + @Override + public T addPathParameter(Object object) { + if (object != null) { + mPathParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addHeaders(String key, String value) { + mHeadersMap.put(key, value); + return (T) this; + } + + @Override + public T addHeaders(Map headerMap) { + if (headerMap != null) { + mHeadersMap.putAll(headerMap); + } + return (T) this; + } + + @Override + public T addHeaders(Object object) { + if (object != null) { + mHeadersMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T doNotCacheResponse() { + mCacheControl = new CacheControl.Builder().noStore().build(); + return (T) this; + } + + @Override + public T getResponseOnlyIfCached() { + mCacheControl = CacheControl.FORCE_CACHE; + return (T) this; + } + + @Override + public T getResponseOnlyFromNetwork() { + mCacheControl = CacheControl.FORCE_NETWORK; + return (T) this; + } + + @Override + public T setMaxAgeCacheControl(int maxAge, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxAge(maxAge, timeUnit).build(); + return (T) this; + } + + @Override + public T setMaxStaleCacheControl(int maxStale, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxStale(maxStale, timeUnit).build(); + return (T) this; + } + + @Override + public T setExecutor(Executor executor) { + mExecutor = executor; + return (T) this; + } + + @Override + public T setOkHttpClient(OkHttpClient okHttpClient) { + mOkHttpClient = okHttpClient; + return (T) this; + } + + @Override + public T setUserAgent(String userAgent) { + mUserAgent = userAgent; + return (T) this; + } + + public T addBodyParameter(String key, String value) { + mBodyParameterMap.put(key, value); + return (T) this; + } + + public T addBodyParameter(Map bodyParameterMap) { + if (bodyParameterMap != null) { + mBodyParameterMap.putAll(bodyParameterMap); + } + return (T) this; + } + + public T addBodyParameter(Object object) { + if (object != null) { + mBodyParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + public T addUrlEncodeFormBodyParameter(String key, String value) { + mUrlEncodedFormBodyParameterMap.put(key, value); + return (T) this; + } + + public T addUrlEncodeFormBodyParameter(Map bodyParameterMap) { + if (bodyParameterMap != null) { + mUrlEncodedFormBodyParameterMap.putAll(bodyParameterMap); + } + return (T) this; + } + + public T addUrlEncodeFormBodyParameter(Object object) { + if (object != null) { + mUrlEncodedFormBodyParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + public T addApplicationJsonBody(Object object) { + if (object != null) { + mApplicationJsonString = ParseUtil + .getParserFactory() + .getString(object); + } + return (T) this; + } + + public T addJSONObjectBody(JSONObject jsonObject) { + if (jsonObject != null) { + mApplicationJsonString = jsonObject.toString(); + } + return (T) this; + } + + public T addJSONArrayBody(JSONArray jsonArray) { + if (jsonArray != null) { + mApplicationJsonString = jsonArray.toString(); + } + return (T) this; + } + + public T addStringBody(String stringBody) { + mStringBody = stringBody; + return (T) this; + } + + public T addFileBody(File file) { + mFile = file; + return (T) this; + } + + public T addByteBody(byte[] bytes) { + mByte = bytes; + return (T) this; + } + + public T setContentType(String contentType) { + mCustomContentType = contentType; + return (T) this; + } + + public ANRequest build() { + return new ANRequest(this); + } + } + + public static class DownloadBuilder implements RequestBuilder { + + private Priority mPriority = Priority.MEDIUM; + private String mUrl; + private Object mTag; + private HashMap mHeadersMap = new HashMap<>(); + private HashMap mQueryParameterMap = new HashMap<>(); + private HashMap mPathParameterMap = new HashMap<>(); + private String mDirPath; + private String mFileName; + private CacheControl mCacheControl; + private int mPercentageThresholdForCancelling = 0; + private Executor mExecutor; + private OkHttpClient mOkHttpClient; + private String mUserAgent; + + public DownloadBuilder(String url, String dirPath, String fileName) { + this.mUrl = url; + this.mDirPath = dirPath; + this.mFileName = fileName; + } + + @Override + public T setPriority(Priority priority) { + mPriority = priority; + return (T) this; + } + + @Override + public T setTag(Object tag) { + mTag = tag; + return (T) this; + } + + @Override + public T addHeaders(String key, String value) { + mHeadersMap.put(key, value); + return (T) this; + } + + @Override + public T addHeaders(Map headerMap) { + if (headerMap != null) { + mHeadersMap.putAll(headerMap); + } + return (T) this; + } + + @Override + public T addHeaders(Object object) { + if (object != null) { + mHeadersMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addQueryParameter(String key, String value) { + mQueryParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addQueryParameter(Map queryParameterMap) { + if (queryParameterMap != null) { + mQueryParameterMap.putAll(queryParameterMap); + } + return (T) this; + } + + @Override + public T addQueryParameter(Object object) { + if (object != null) { + mQueryParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addPathParameter(String key, String value) { + mPathParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addPathParameter(Map pathParameterMap) { + if (pathParameterMap != null) { + mPathParameterMap.putAll(pathParameterMap); + } + return (T) this; + } + + @Override + public T addPathParameter(Object object) { + if (object != null) { + mPathParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T doNotCacheResponse() { + mCacheControl = new CacheControl.Builder().noStore().build(); + return (T) this; + } + + @Override + public T getResponseOnlyIfCached() { + mCacheControl = CacheControl.FORCE_CACHE; + return (T) this; + } + + @Override + public T getResponseOnlyFromNetwork() { + mCacheControl = CacheControl.FORCE_NETWORK; + return (T) this; + } + + @Override + public T setMaxAgeCacheControl(int maxAge, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxAge(maxAge, timeUnit).build(); + return (T) this; + } + + @Override + public T setMaxStaleCacheControl(int maxStale, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxStale(maxStale, timeUnit).build(); + return (T) this; + } + + @Override + public T setExecutor(Executor executor) { + mExecutor = executor; + return (T) this; + } + + @Override + public T setOkHttpClient(OkHttpClient okHttpClient) { + mOkHttpClient = okHttpClient; + return (T) this; + } + + @Override + public T setUserAgent(String userAgent) { + mUserAgent = userAgent; + return (T) this; + } + + public T setPercentageThresholdForCancelling(int percentageThresholdForCancelling) { + mPercentageThresholdForCancelling = percentageThresholdForCancelling; + return (T) this; + } + + public ANRequest build() { + return new ANRequest(this); + } + } + + public static class MultiPartBuilder implements RequestBuilder { + + private Priority mPriority = Priority.MEDIUM; + private String mUrl; + private Object mTag; + private HashMap mHeadersMap = new HashMap<>(); + private HashMap mMultiPartParameterMap = new HashMap<>(); + private HashMap mQueryParameterMap = new HashMap<>(); + private HashMap mPathParameterMap = new HashMap<>(); + private HashMap mMultiPartFileMap = new HashMap<>(); + private CacheControl mCacheControl; + private int mPercentageThresholdForCancelling = 0; + private Executor mExecutor; + private OkHttpClient mOkHttpClient; + private String mUserAgent; + private String mCustomContentType; + + public MultiPartBuilder(String url) { + this.mUrl = url; + } + + @Override + public T setPriority(Priority priority) { + mPriority = priority; + return (T) this; + } + + @Override + public T setTag(Object tag) { + mTag = tag; + return (T) this; + } + + @Override + public T addQueryParameter(String key, String value) { + mQueryParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addQueryParameter(Map queryParameterMap) { + if (queryParameterMap != null) { + mQueryParameterMap.putAll(queryParameterMap); + } + return (T) this; + } + + @Override + public T addQueryParameter(Object object) { + if (object != null) { + mQueryParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addPathParameter(String key, String value) { + mPathParameterMap.put(key, value); + return (T) this; + } + + @Override + public T addPathParameter(Map pathParameterMap) { + if (pathParameterMap != null) { + mPathParameterMap.putAll(pathParameterMap); + } + return (T) this; + } + + @Override + public T addPathParameter(Object object) { + if (object != null) { + mPathParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T addHeaders(String key, String value) { + mHeadersMap.put(key, value); + return (T) this; + } + + @Override + public T addHeaders(Map headerMap) { + if (headerMap != null) { + mHeadersMap.putAll(headerMap); + } + return (T) this; + } + + @Override + public T addHeaders(Object object) { + if (object != null) { + mHeadersMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + @Override + public T doNotCacheResponse() { + mCacheControl = new CacheControl.Builder().noStore().build(); + return (T) this; + } + + @Override + public T getResponseOnlyIfCached() { + mCacheControl = CacheControl.FORCE_CACHE; + return (T) this; + } + + @Override + public T getResponseOnlyFromNetwork() { + mCacheControl = CacheControl.FORCE_NETWORK; + return (T) this; + } + + @Override + public T setMaxAgeCacheControl(int maxAge, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxAge(maxAge, timeUnit).build(); + return (T) this; + } + + @Override + public T setMaxStaleCacheControl(int maxStale, TimeUnit timeUnit) { + mCacheControl = new CacheControl.Builder().maxStale(maxStale, timeUnit).build(); + return (T) this; + } + + @Override + public T setExecutor(Executor executor) { + mExecutor = executor; + return (T) this; + } + + @Override + public T setOkHttpClient(OkHttpClient okHttpClient) { + mOkHttpClient = okHttpClient; + return (T) this; + } + + @Override + public T setUserAgent(String userAgent) { + mUserAgent = userAgent; + return (T) this; + } + + public T addMultipartParameter(String key, String value) { + mMultiPartParameterMap.put(key, value); + return (T) this; + } + + public T addMultipartParameter(Map multiPartParameterMap) { + if (multiPartParameterMap != null) { + mMultiPartParameterMap.putAll(multiPartParameterMap); + } + return (T) this; + } + + public T addMultipartParameter(Object object) { + if (object != null) { + mMultiPartParameterMap.putAll(ParseUtil + .getParserFactory() + .getStringMap(object)); + } + return (T) this; + } + + public T addMultipartFile(String key, File file) { + mMultiPartFileMap.put(key, file); + return (T) this; + } + + public T addMultipartFile(Map multiPartFileMap) { + if (multiPartFileMap != null) { + mMultiPartFileMap.putAll(multiPartFileMap); + } + return (T) this; + } + + public T setPercentageThresholdForCancelling(int percentageThresholdForCancelling) { + this.mPercentageThresholdForCancelling = percentageThresholdForCancelling; + return (T) this; + } + + public T setContentType(String contentType) { + mCustomContentType = contentType; + return (T) this; + } + + public ANRequest build() { + return new ANRequest(this); + } + } + + @Override + public String toString() { + return "ANRequest{" + + "sequenceNumber='" + sequenceNumber + + ", mMethod=" + mMethod + + ", mPriority=" + mPriority + + ", mRequestType=" + mRequestType + + ", mUrl=" + mUrl + + '}'; + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java b/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java new file mode 100644 index 0000000..be2dfa9 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +import com.androidnetworking.error.ANError; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class ANResponse { + + private final T mResult; + + private final ANError mANError; + + private Response response; + + public static ANResponse success(T result) { + return new ANResponse<>(result); + } + + public static ANResponse failed(ANError anError) { + return new ANResponse<>(anError); + } + + public ANResponse(T result) { + this.mResult = result; + this.mANError = null; + } + + public ANResponse(ANError anError) { + this.mResult = null; + this.mANError = anError; + } + + public T getResult() { + return mResult; + } + + public boolean isSuccess() { + return mANError == null; + } + + public ANError getError() { + return mANError; + } + + public void setOkHttpResponse(Response response) { + this.response = response; + } + + public Response getOkHttpResponse() { + return response; + } + +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java b/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java new file mode 100644 index 0000000..5d94716 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +import com.androidnetworking.core.Core; +import com.androidnetworking.interfaces.ConnectionQualityChangeListener; + +/** + * Created by amitshekhar on 29/05/16. + */ +public class ConnectionClassManager { + + private static final int BYTES_TO_BITS = 8; + private static final int DEFAULT_SAMPLES_TO_QUALITY_CHANGE = 5; + private static final int MINIMUM_SAMPLES_TO_DECIDE_QUALITY = 2; + private static final int DEFAULT_POOR_BANDWIDTH = 150; + private static final int DEFAULT_MODERATE_BANDWIDTH = 550; + private static final int DEFAULT_GOOD_BANDWIDTH = 2000; + private static final long BANDWIDTH_LOWER_BOUND = 10; + + private static ConnectionClassManager sInstance; + private ConnectionQuality mCurrentConnectionQuality = ConnectionQuality.UNKNOWN; + private int mCurrentBandwidthForSampling = 0; + private int mCurrentNumberOfSample = 0; + private int mCurrentBandwidth = 0; + private ConnectionQualityChangeListener mConnectionQualityChangeListener; + + public static ConnectionClassManager getInstance() { + if (sInstance == null) { + synchronized (ConnectionClassManager.class) { + if (sInstance == null) { + sInstance = new ConnectionClassManager(); + } + } + } + return sInstance; + } + + public synchronized void updateBandwidth(long bytes, long timeInMs) { + if (timeInMs == 0 || bytes < 20000 || (bytes) * 1.0 / (timeInMs) * + BYTES_TO_BITS < BANDWIDTH_LOWER_BOUND) { + return; + } + double bandwidth = (bytes) * 1.0 / (timeInMs) * BYTES_TO_BITS; + mCurrentBandwidthForSampling = (int) ((mCurrentBandwidthForSampling * + mCurrentNumberOfSample + bandwidth) / (mCurrentNumberOfSample + 1)); + mCurrentNumberOfSample++; + if (mCurrentNumberOfSample == DEFAULT_SAMPLES_TO_QUALITY_CHANGE || + (mCurrentConnectionQuality == ConnectionQuality.UNKNOWN && + mCurrentNumberOfSample == MINIMUM_SAMPLES_TO_DECIDE_QUALITY)) { + final ConnectionQuality lastConnectionQuality = mCurrentConnectionQuality; + mCurrentBandwidth = mCurrentBandwidthForSampling; + if (mCurrentBandwidthForSampling <= 0) { + mCurrentConnectionQuality = ConnectionQuality.UNKNOWN; + } else if (mCurrentBandwidthForSampling < DEFAULT_POOR_BANDWIDTH) { + mCurrentConnectionQuality = ConnectionQuality.POOR; + } else if (mCurrentBandwidthForSampling < DEFAULT_MODERATE_BANDWIDTH) { + mCurrentConnectionQuality = ConnectionQuality.MODERATE; + } else if (mCurrentBandwidthForSampling < DEFAULT_GOOD_BANDWIDTH) { + mCurrentConnectionQuality = ConnectionQuality.GOOD; + } else if (mCurrentBandwidthForSampling > DEFAULT_GOOD_BANDWIDTH) { + mCurrentConnectionQuality = ConnectionQuality.EXCELLENT; + } + if (mCurrentNumberOfSample == DEFAULT_SAMPLES_TO_QUALITY_CHANGE) { + mCurrentBandwidthForSampling = 0; + mCurrentNumberOfSample = 0; + } + if (mCurrentConnectionQuality != lastConnectionQuality && + mConnectionQualityChangeListener != null) { + Core.getInstance().getExecutorSupplier().forMainThreadTasks() + .execute(new Runnable() { + @Override + public void run() { + mConnectionQualityChangeListener + .onChange(mCurrentConnectionQuality, mCurrentBandwidth); + } + }); + } + } + + } + + public int getCurrentBandwidth() { + return mCurrentBandwidth; + } + + public ConnectionQuality getCurrentConnectionQuality() { + return mCurrentConnectionQuality; + } + + public void setListener(ConnectionQualityChangeListener connectionQualityChangeListener) { + mConnectionQualityChangeListener = connectionQualityChangeListener; + } + + public void removeListener() { + mConnectionQualityChangeListener = null; + } + + public static void shutDown() { + if (sInstance != null) { + sInstance = null; + } + } + +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java b/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java new file mode 100644 index 0000000..805d8a9 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +/** + * Created by amitshekhar on 29/05/16. + */ +public enum ConnectionQuality { + /** + * Bandwidth under 150 kbps. + */ + POOR, + /** + * Bandwidth between 150 and 550 kbps. + */ + MODERATE, + /** + * Bandwidth between 550 and 2000 kbps. + */ + GOOD, + /** + * EXCELLENT - Bandwidth over 2000 kbps. + */ + EXCELLENT, + /** + * Placeholder for unknown bandwidth. This is the initial value and will stay at this value + * if a bandwidth cannot be accurately found. + */ + UNKNOWN +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/Method.java b/android-networking/src/main/java/com/androidnetworking/common/Method.java new file mode 100644 index 0000000..1e05a17 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/Method.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +/** + * Created by amitshekhar on 26/03/16. + */ +public interface Method { + int GET = 0; + int POST = 1; + int PUT = 2; + int DELETE = 3; + int HEAD = 4; + int PATCH = 5; +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/Priority.java b/android-networking/src/main/java/com/androidnetworking/common/Priority.java new file mode 100644 index 0000000..3b37a5a --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/Priority.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +/** + * Created by amitshekhar on 22/03/16. + */ + + +/** + * Priority levels recognized by the request server. + */ +public enum Priority { + /** + * NOTE: DO NOT CHANGE ORDERING OF THOSE CONSTANTS UNDER ANY CIRCUMSTANCES. + * Doing so will make ordering incorrect. + */ + + /** + * Lowest priority level. Used for prefetches of data. + */ + LOW, + + /** + * Medium priority level. Used for warming of data that might soon get visible. + */ + MEDIUM, + + /** + * Highest priority level. Used for data that are currently visible on screen. + */ + HIGH, + + /** + * Highest priority level. Used for data that are required instantly(mainly for emergency). + */ + IMMEDIATE + +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java b/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java new file mode 100644 index 0000000..9e1adf3 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; + +/** + * Created by amitshekhar on 26/03/16. + */ +public interface RequestBuilder { + + RequestBuilder setPriority(Priority priority); + + RequestBuilder setTag(Object tag); + + RequestBuilder addHeaders(String key, String value); + + RequestBuilder addHeaders(Map headerMap); + + RequestBuilder addHeaders(Object object); + + RequestBuilder addQueryParameter(String key, String value); + + RequestBuilder addQueryParameter(Map queryParameterMap); + + RequestBuilder addQueryParameter(Object object); + + RequestBuilder addPathParameter(String key, String value); + + RequestBuilder addPathParameter(Map pathParameterMap); + + RequestBuilder addPathParameter(Object object); + + RequestBuilder doNotCacheResponse(); + + RequestBuilder getResponseOnlyIfCached(); + + RequestBuilder getResponseOnlyFromNetwork(); + + RequestBuilder setMaxAgeCacheControl(int maxAge, TimeUnit timeUnit); + + RequestBuilder setMaxStaleCacheControl(int maxStale, TimeUnit timeUnit); + + RequestBuilder setExecutor(Executor executor); + + RequestBuilder setOkHttpClient(OkHttpClient okHttpClient); + + RequestBuilder setUserAgent(String userAgent); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/RequestType.java b/android-networking/src/main/java/com/androidnetworking/common/RequestType.java new file mode 100644 index 0000000..9a928d0 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/RequestType.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +/** + * Created by amitshekhar on 04/04/16. + */ +public interface RequestType { + int SIMPLE = 0; + int DOWNLOAD = 1; + int MULTIPART = 2; +} diff --git a/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java b/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java new file mode 100644 index 0000000..36491e6 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.common; + +/** + * Created by amitshekhar on 26/03/16. + */ +public enum ResponseType { + STRING, + JSON_OBJECT, + JSON_ARRAY, + OK_HTTP_RESPONSE, + BITMAP, + PREFETCH, + PARSED +} diff --git a/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java b/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java new file mode 100644 index 0000000..47c3e5d --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.core; + +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.telephony.TelephonyManager; + +import com.androidnetworking.common.Priority; +import com.androidnetworking.internal.InternalRunnable; + +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class ANExecutor extends ThreadPoolExecutor { + + private static final int DEFAULT_THREAD_COUNT = 3; + + ANExecutor(int maxNumThreads, ThreadFactory threadFactory) { + super(maxNumThreads, maxNumThreads, 0, TimeUnit.MILLISECONDS, + new PriorityBlockingQueue(), threadFactory); + } + + + void adjustThreadCount(NetworkInfo info) { + if (info == null || !info.isConnectedOrConnecting()) { + setThreadCount(DEFAULT_THREAD_COUNT); + return; + } + switch (info.getType()) { + case ConnectivityManager.TYPE_WIFI: + case ConnectivityManager.TYPE_WIMAX: + case ConnectivityManager.TYPE_ETHERNET: + setThreadCount(4); + break; + case ConnectivityManager.TYPE_MOBILE: + switch (info.getSubtype()) { + case TelephonyManager.NETWORK_TYPE_LTE: // 4G + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_EHRPD: + setThreadCount(3); + break; + case TelephonyManager.NETWORK_TYPE_UMTS: // 3G + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + setThreadCount(2); + break; + case TelephonyManager.NETWORK_TYPE_GPRS: // 2G + case TelephonyManager.NETWORK_TYPE_EDGE: + setThreadCount(1); + break; + default: + setThreadCount(DEFAULT_THREAD_COUNT); + } + break; + default: + setThreadCount(DEFAULT_THREAD_COUNT); + } + } + + private void setThreadCount(int threadCount) { + setCorePoolSize(threadCount); + setMaximumPoolSize(threadCount); + } + + @Override + public Future submit(Runnable task) { + AndroidNetworkingFutureTask futureTask = new AndroidNetworkingFutureTask((InternalRunnable) task); + execute(futureTask); + return futureTask; + } + + private static final class AndroidNetworkingFutureTask extends FutureTask + implements Comparable { + private final InternalRunnable hunter; + + public AndroidNetworkingFutureTask(InternalRunnable hunter) { + super(hunter, null); + this.hunter = hunter; + } + + @Override + public int compareTo(AndroidNetworkingFutureTask other) { + Priority p1 = hunter.getPriority(); + Priority p2 = other.hunter.getPriority(); + return (p1 == p2 ? hunter.sequence - other.hunter.sequence : p2.ordinal() - p1.ordinal()); + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/core/Core.java b/android-networking/src/main/java/com/androidnetworking/core/Core.java new file mode 100644 index 0000000..673b24f --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/core/Core.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.core; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class Core { + + private static Core sInstance = null; + private final ExecutorSupplier mExecutorSupplier; + + private Core() { + this.mExecutorSupplier = new DefaultExecutorSupplier(); + } + + public static Core getInstance() { + if (sInstance == null) { + synchronized (Core.class) { + if (sInstance == null) { + sInstance = new Core(); + } + } + } + return sInstance; + } + + public ExecutorSupplier getExecutorSupplier() { + return mExecutorSupplier; + } + + public static void shutDown() { + if (sInstance != null) { + sInstance = null; + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java b/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java new file mode 100644 index 0000000..9cec863 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.core; + +import android.os.Process; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadFactory; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class DefaultExecutorSupplier implements ExecutorSupplier { + + public static final int DEFAULT_MAX_NUM_THREADS = 2 * Runtime.getRuntime().availableProcessors() + 1; + private final ANExecutor mNetworkExecutor; + private final ANExecutor mImmediateNetworkExecutor; + private final Executor mMainThreadExecutor; + + public DefaultExecutorSupplier() { + ThreadFactory backgroundPriorityThreadFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND); + mNetworkExecutor = new ANExecutor(DEFAULT_MAX_NUM_THREADS, backgroundPriorityThreadFactory); + mImmediateNetworkExecutor = new ANExecutor(2, backgroundPriorityThreadFactory); + mMainThreadExecutor = new MainThreadExecutor(); + } + + @Override + public ANExecutor forNetworkTasks() { + return mNetworkExecutor; + } + + @Override + public ANExecutor forImmediateNetworkTasks() { + return mImmediateNetworkExecutor; + } + + @Override + public Executor forMainThreadTasks() { + return mMainThreadExecutor; + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java b/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java new file mode 100644 index 0000000..cddd115 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.core; + +import java.util.concurrent.Executor; + +/** + * Created by amitshekhar on 22/03/16. + */ +public interface ExecutorSupplier { + + ANExecutor forNetworkTasks(); + + ANExecutor forImmediateNetworkTasks(); + + Executor forMainThreadTasks(); +} diff --git a/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java b/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java new file mode 100644 index 0000000..aa227cb --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.core; + +import android.os.Handler; +import android.os.Looper; + +import java.util.concurrent.Executor; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class MainThreadExecutor implements Executor { + + private final Handler handler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(Runnable runnable) { + handler.post(runnable); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java b/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java new file mode 100644 index 0000000..3eacf9c --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.core; + +/** + * Created by amitshekhar on 22/03/16. + */ + + +import android.os.Process; + +import java.util.concurrent.ThreadFactory; + +public class PriorityThreadFactory implements ThreadFactory { + + private final int mThreadPriority; + + public PriorityThreadFactory(int threadPriority) { + mThreadPriority = threadPriority; + } + + @Override + public Thread newThread(final Runnable runnable) { + Runnable wrapperRunnable = new Runnable() { + @Override + public void run() { + try { + Process.setThreadPriority(mThreadPriority); + } catch (Throwable t) { + + } + runnable.run(); + } + }; + return new Thread(wrapperRunnable); + } + +} diff --git a/android-networking/src/main/java/com/androidnetworking/error/ANError.java b/android-networking/src/main/java/com/androidnetworking/error/ANError.java new file mode 100644 index 0000000..399e827 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/error/ANError.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.error; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.utils.ParseUtil; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 22/03/16. + */ +@SuppressWarnings({"unchecked", "unused"}) +public class ANError extends Exception { + + private String errorBody; + + private int errorCode = 0; + + private String errorDetail; + + private Response response; + + public ANError() { + } + + public ANError(Response response) { + this.response = response; + } + + public ANError(String message) { + super(message); + } + + public ANError(String message, Response response) { + super(message); + this.response = response; + } + + public ANError(String message, Throwable throwable) { + super(message, throwable); + } + + public ANError(String message, Response response, Throwable throwable) { + super(message, throwable); + this.response = response; + } + + public ANError(Response response, Throwable throwable) { + super(throwable); + this.response = response; + } + + public ANError(Throwable throwable) { + super(throwable); + } + + public Response getResponse() { + return response; + } + + public void setErrorDetail(String errorDetail) { + this.errorDetail = errorDetail; + } + + public String getErrorDetail() { + return this.errorDetail; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public int getErrorCode() { + return this.errorCode; + } + + public void setCancellationMessageInError() { + this.errorDetail = ANConstants.REQUEST_CANCELLED_ERROR; + } + + public String getErrorBody() { + return errorBody; + } + + public void setErrorBody(String errorBody) { + this.errorBody = errorBody; + } + + public T getErrorAsObject(Class objectClass) { + try { + return (T) (ParseUtil + .getParserFactory() + .getObject(errorBody, objectClass)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java new file mode 100644 index 0000000..1229ccc --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java @@ -0,0 +1,91 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.gsonparserfactory; + +import com.androidnetworking.interfaces.Parser; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.HashMap; + +import okhttp3.RequestBody; +import okhttp3.ResponseBody; + +/** + * Created by amitshekhar on 31/07/16. + */ +public final class GsonParserFactory extends Parser.Factory { + + private final Gson gson; + + public GsonParserFactory() { + this.gson = new Gson(); + } + + public GsonParserFactory(Gson gson) { + this.gson = gson; + } + + @Override + public Parser responseBodyParser(Type type) { + TypeAdapter adapter = gson.getAdapter(TypeToken.get(type)); + return new GsonResponseBodyParser<>(gson, adapter); + } + + @Override + public Parser requestBodyParser(Type type) { + TypeAdapter adapter = gson.getAdapter(TypeToken.get(type)); + return new GsonRequestBodyParser<>(gson, adapter); + } + + @Override + public Object getObject(String string, Type type) { + try { + return gson.fromJson(string, type); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public String getString(Object object) { + try { + return gson.toJson(object); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + @Override + public HashMap getStringMap(Object object) { + try { + Type type = new TypeToken>() { + }.getType(); + return gson.fromJson(gson.toJson(object), type); + } catch (Exception e) { + e.printStackTrace(); + } + return new HashMap<>(); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java new file mode 100644 index 0000000..5b0f221 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java @@ -0,0 +1,60 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.gsonparserfactory; + +import com.androidnetworking.interfaces.Parser; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.Charset; + +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okio.Buffer; + +/** + * Created by amitshekhar on 31/07/16. + */ +final class GsonRequestBodyParser implements Parser { + private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + private final Gson gson; + private final TypeAdapter adapter; + + GsonRequestBodyParser(Gson gson, TypeAdapter adapter) { + this.gson = gson; + this.adapter = adapter; + } + + @Override + public RequestBody convert(T value) throws IOException { + Buffer buffer = new Buffer(); + Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8); + JsonWriter jsonWriter = gson.newJsonWriter(writer); + adapter.write(jsonWriter, value); + jsonWriter.close(); + return RequestBody.create(MEDIA_TYPE, buffer.readByteString()); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java new file mode 100644 index 0000000..d41df27 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java @@ -0,0 +1,52 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.gsonparserfactory; + +import com.androidnetworking.interfaces.Parser; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; + +import java.io.IOException; + +import okhttp3.ResponseBody; + +/** + * Created by amitshekhar on 31/07/16. + */ +final class GsonResponseBodyParser implements Parser { + private final Gson gson; + private final TypeAdapter adapter; + + GsonResponseBodyParser(Gson gson, TypeAdapter adapter) { + this.gson = gson; + this.adapter = adapter; + } + + @Override + public T convert(ResponseBody value) throws IOException { + JsonReader jsonReader = gson.newJsonReader(value.charStream()); + try { + return adapter.read(jsonReader); + } finally { + value.close(); + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java b/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java new file mode 100644 index 0000000..bb2453a --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interceptors; + +import java.io.IOException; + +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okio.Buffer; +import okio.BufferedSink; +import okio.GzipSink; +import okio.Okio; + +/** + * Created by amitshekhar on 02/05/16. + */ +public class GzipRequestInterceptor implements Interceptor { + @Override + public Response intercept(Chain chain) throws IOException { + Request originalRequest = chain.request(); + if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { + return chain.proceed(originalRequest); + } + + Request compressedRequest = originalRequest.newBuilder() + .header("Content-Encoding", "gzip") + .method(originalRequest.method(), forceContentLength(gzip(originalRequest.body()))) + .build(); + return chain.proceed(compressedRequest); + } + + private RequestBody forceContentLength(final RequestBody requestBody) throws IOException { + final Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + return new RequestBody() { + @Override + public MediaType contentType() { + return requestBody.contentType(); + } + + @Override + public long contentLength() { + return buffer.size(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + sink.write(buffer.snapshot()); + } + }; + } + + + private RequestBody gzip(final RequestBody body) { + return new RequestBody() { + @Override + public MediaType contentType() { + return body.contentType(); + } + + @Override + public long contentLength() { + return -1; // We don't know the compressed length in advance! + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); + body.writeTo(gzipSink); + gzipSink.close(); + } + }; + } +} \ No newline at end of file diff --git a/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java b/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java new file mode 100644 index 0000000..44f5265 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java @@ -0,0 +1,302 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interceptors; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.concurrent.TimeUnit; + +import okhttp3.Connection; +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okhttp3.internal.http.HttpHeaders; +import okhttp3.internal.platform.Platform; +import okio.Buffer; +import okio.BufferedSource; + +import static okhttp3.internal.platform.Platform.INFO; + +/** + * Created by amitshekhar on 31/01/17. + */ + +public class HttpLoggingInterceptor implements Interceptor { + + private static final Charset UTF8 = Charset.forName("UTF-8"); + + public enum Level { + /** + * No logs. + */ + NONE, + /** + * Logs request and response lines. + *

+ *

Example: + *

{@code
+         * --> POST /greeting http/1.1 (3-byte body)
+         *
+         * <-- 200 OK (22ms, 6-byte body)
+         * }
+ */ + BASIC, + /** + * Logs request and response lines and their respective headers. + *

+ *

Example: + *

{@code
+         * --> POST /greeting http/1.1
+         * Host: example.com
+         * Content-Type: plain/text
+         * Content-Length: 3
+         * --> END POST
+         *
+         * <-- 200 OK (22ms)
+         * Content-Type: plain/text
+         * Content-Length: 6
+         * <-- END HTTP
+         * }
+ */ + HEADERS, + /** + * Logs request and response lines and their respective headers and bodies (if present). + *

+ *

Example: + *

{@code
+         * --> POST /greeting http/1.1
+         * Host: example.com
+         * Content-Type: plain/text
+         * Content-Length: 3
+         *
+         * Hi?
+         * --> END POST
+         *
+         * <-- 200 OK (22ms)
+         * Content-Type: plain/text
+         * Content-Length: 6
+         *
+         * Hello!
+         * <-- END HTTP
+         * }
+ */ + BODY + } + + public interface Logger { + void log(String message); + + /** + * A {@link Logger} defaults output appropriate for the current platform. + */ + Logger DEFAULT = new Logger() { + @Override + public void log(String message) { + Platform.get().log(INFO, message, null); + } + }; + } + + public HttpLoggingInterceptor() { + this(Logger.DEFAULT); + } + + public HttpLoggingInterceptor(Logger logger) { + this.logger = logger; + } + + private final Logger logger; + + private volatile Level level = Level.NONE; + + /** + * Change the level at which this interceptor logs. + */ + public HttpLoggingInterceptor setLevel(Level level) { + if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); + this.level = level; + return this; + } + + public Level getLevel() { + return level; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Level level = this.level; + + Request request = chain.request(); + if (level == Level.NONE) { + return chain.proceed(request); + } + + boolean logBody = level == Level.BODY; + boolean logHeaders = logBody || level == Level.HEADERS; + + RequestBody requestBody = request.body(); + boolean hasRequestBody = requestBody != null; + + Connection connection = chain.connection(); + Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; + String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol; + if (!logHeaders && hasRequestBody) { + requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; + } + logger.log(requestStartMessage); + + if (logHeaders) { + if (hasRequestBody) { + // Request body headers are only present when installed as a network interceptor. Force + // them to be included (when available) so there values are known. + if (requestBody.contentType() != null) { + logger.log("Content-Type: " + requestBody.contentType()); + } + if (requestBody.contentLength() != -1) { + logger.log("Content-Length: " + requestBody.contentLength()); + } + } + + Headers headers = request.headers(); + for (int i = 0, count = headers.size(); i < count; i++) { + String name = headers.name(i); + // Skip headers from the request body as they are explicitly logged above. + if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { + logger.log(name + ": " + headers.value(i)); + } + } + + if (!logBody || !hasRequestBody) { + logger.log("--> END " + request.method()); + } else if (bodyEncoded(request.headers())) { + logger.log("--> END " + request.method() + " (encoded body omitted)"); + } else { + Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + + Charset charset = UTF8; + MediaType contentType = requestBody.contentType(); + if (contentType != null) { + charset = contentType.charset(UTF8); + } + + logger.log(""); + if (isPlaintext(buffer)) { + logger.log(buffer.readString(charset)); + logger.log("--> END " + request.method() + + " (" + requestBody.contentLength() + "-byte body)"); + } else { + logger.log("--> END " + request.method() + " (binary " + + requestBody.contentLength() + "-byte body omitted)"); + } + } + } + + long startNs = System.nanoTime(); + Response response; + try { + response = chain.proceed(request); + } catch (Exception e) { + logger.log("<-- HTTP FAILED: " + e); + throw e; + } + long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); + + ResponseBody responseBody = response.body(); + long contentLength = responseBody.contentLength(); + String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; + logger.log("<-- " + response.code() + ' ' + response.message() + ' ' + + response.request().url() + " (" + tookMs + "ms" + (!logHeaders ? ", " + + bodySize + " body" : "") + ')'); + + if (logHeaders) { + Headers headers = response.headers(); + for (int i = 0, count = headers.size(); i < count; i++) { + logger.log(headers.name(i) + ": " + headers.value(i)); + } + + if (!logBody || !HttpHeaders.hasBody(response)) { + logger.log("<-- END HTTP"); + } else if (bodyEncoded(response.headers())) { + logger.log("<-- END HTTP (encoded body omitted)"); + } else { + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + Buffer buffer = source.buffer(); + + Charset charset = UTF8; + MediaType contentType = responseBody.contentType(); + if (contentType != null) { + charset = contentType.charset(UTF8); + } + + if (!isPlaintext(buffer)) { + logger.log(""); + logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)"); + return response; + } + + if (contentLength != 0) { + logger.log(""); + logger.log(buffer.clone().readString(charset)); + } + + logger.log("<-- END HTTP (" + buffer.size() + "-byte body)"); + } + } + + return response; + } + + /** + * Returns true if the body in question probably contains human readable text. Uses a small sample + * of code points to detect unicode control characters commonly used in binary file signatures. + */ + static boolean isPlaintext(Buffer buffer) { + try { + Buffer prefix = new Buffer(); + long byteCount = buffer.size() < 64 ? buffer.size() : 64; + buffer.copyTo(prefix, 0, byteCount); + for (int i = 0; i < 16; i++) { + if (prefix.exhausted()) { + break; + } + int codePoint = prefix.readUtf8CodePoint(); + if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { + return false; + } + } + return true; + } catch (EOFException e) { + return false; // Truncated UTF-8 sequence. + } + } + + private boolean bodyEncoded(Headers headers) { + String contentEncoding = headers.get("Content-Encoding"); + return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java new file mode 100644 index 0000000..54aa9f2 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +/** + * Created by amitshekhar on 31/05/16. + */ +public interface AnalyticsListener { + + void onReceived(long timeTakenInMillis, long bytesSent, long bytesReceived, boolean isFromCache); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java new file mode 100644 index 0000000..6cdc307 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +import android.graphics.Bitmap; + +import com.androidnetworking.error.ANError; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface BitmapRequestListener { + + void onResponse(Bitmap response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java new file mode 100644 index 0000000..05c3bc3 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +import com.androidnetworking.common.ConnectionQuality; + +/** + * Created by amitshekhar on 29/05/16. + */ +public interface ConnectionQualityChangeListener { + + void onChange(ConnectionQuality currentConnectionQuality, int currentBandwidth); +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java new file mode 100644 index 0000000..1915a00 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +/** + * Created by amitshekhar on 29/04/16. + */ +public interface DownloadListener { + + void onDownloadComplete(); + + void onError(ANError anError); +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java new file mode 100644 index 0000000..4406ee9 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +/** + * Created by amitshekhar on 30/03/16. + */ +public interface DownloadProgressListener { + void onProgress(long bytesDownloaded, long totalBytes); +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java new file mode 100644 index 0000000..e20e913 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import org.json.JSONArray; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface JSONArrayRequestListener { + + void onResponse(JSONArray response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java new file mode 100644 index 0000000..d1b7981 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import org.json.JSONObject; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface JSONObjectRequestListener { + + void onResponse(JSONObject response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java new file mode 100644 index 0000000..2df552e --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java @@ -0,0 +1,37 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import android.graphics.Bitmap; + +import com.androidnetworking.error.ANError; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface OkHttpResponseAndBitmapRequestListener { + + void onResponse(Response okHttpResponse, Bitmap response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java new file mode 100644 index 0000000..02b915e --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java @@ -0,0 +1,37 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import org.json.JSONArray; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface OkHttpResponseAndJSONArrayRequestListener { + + void onResponse(Response okHttpResponse, JSONArray response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java new file mode 100644 index 0000000..093e0cb --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java @@ -0,0 +1,37 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import org.json.JSONObject; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface OkHttpResponseAndJSONObjectRequestListener { + + void onResponse(Response okHttpResponse, JSONObject response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java new file mode 100644 index 0000000..8b8a744 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java @@ -0,0 +1,35 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 31/07/16. + */ +public interface OkHttpResponseAndParsedRequestListener { + + void onResponse(Response okHttpResponse, T response); + + void onError(ANError anError); + +} \ No newline at end of file diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java new file mode 100644 index 0000000..ba83d7e --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java @@ -0,0 +1,35 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface OkHttpResponseAndStringRequestListener { + + void onResponse(Response okHttpResponse, String response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java new file mode 100644 index 0000000..448db93 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java @@ -0,0 +1,35 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 22/08/16. + */ +public interface OkHttpResponseListener { + + void onResponse(Response response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java new file mode 100644 index 0000000..bea5f49 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java @@ -0,0 +1,33 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +/** + * Created by amitshekhar on 31/07/16. + */ +public interface ParsedRequestListener { + + void onResponse(T response); + + void onError(ANError anError); + +} \ No newline at end of file diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java b/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java new file mode 100644 index 0000000..19e12dd --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java @@ -0,0 +1,60 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.interfaces; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.HashMap; + +import okhttp3.RequestBody; +import okhttp3.ResponseBody; + +/** + * Created by amitshekhar on 31/07/16. + */ +public interface Parser { + + T convert(F value) throws IOException; + + abstract class Factory { + + public Parser responseBodyParser(Type type) { + return null; + } + + public Parser requestBodyParser(Type type) { + return null; + } + + public Object getObject(String string, Type type) { + return null; + } + + public String getString(Object object) { + return null; + } + + public HashMap getStringMap(Object object) { + return null; + } + + } + +} \ No newline at end of file diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java new file mode 100644 index 0000000..8d644d4 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +import com.androidnetworking.error.ANError; + +/** + * Created by amitshekhar on 23/05/16. + */ +public interface StringRequestListener { + + void onResponse(String response); + + void onError(ANError anError); + +} diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java new file mode 100644 index 0000000..4c2a2e1 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.interfaces; + +/** + * Created by amitshekhar on 21/04/16. + */ +public interface UploadProgressListener { + void onProgress(long bytesUploaded, long totalBytes); +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java b/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java new file mode 100644 index 0000000..d278d54 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Handler; +import android.os.Looper; +import android.widget.ImageView; + +import com.androidnetworking.AndroidNetworking; +import com.androidnetworking.cache.LruBitmapCache; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.BitmapRequestListener; + +import java.util.HashMap; +import java.util.LinkedList; + +/** + * Created by amitshekhar on 23/03/16. + */ +public class ANImageLoader { + + // Get max available VM memory, exceeding this amount will throw an + // OutOfMemory exception. Stored in kilobytes as LruCache takes an + // int in its constructor. + private static final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); + + // Use 1/8th of the available memory for this memory cache. + private static final int cacheSize = maxMemory / 8; + + private int mBatchResponseDelayMs = 100; + + private final ImageCache mCache; + + private final HashMap mInFlightRequests = + new HashMap(); + + private final HashMap mBatchedResponses = + new HashMap(); + + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + private Runnable mRunnable; + + private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); + + private static ANImageLoader sInstance; + + public static void initialize() { + getInstance(); + } + + public static ANImageLoader getInstance() { + if (sInstance == null) { + synchronized (ANImageLoader.class) { + if (sInstance == null) { + sInstance = new ANImageLoader(new LruBitmapCache(cacheSize)); + } + } + } + return sInstance; + } + + public interface ImageCache { + Bitmap getBitmap(String key); + + void putBitmap(String key, Bitmap bitmap); + + void evictBitmap(String key); + + void evictAllBitmap(); + } + + public ANImageLoader(ImageCache imageCache) { + mCache = imageCache; + } + + public ImageCache getImageCache() { + return mCache; + } + + public static ImageListener getImageListener(final ImageView view, + final int defaultImageResId, + final int errorImageResId) { + return new ImageListener() { + @Override + public void onResponse(ImageContainer response, boolean isImmediate) { + if (response.getBitmap() != null) { + view.setImageBitmap(response.getBitmap()); + } else if (defaultImageResId != 0) { + view.setImageResource(defaultImageResId); + } + } + + @Override + public void onError(ANError anError) { + if (errorImageResId != 0) { + view.setImageResource(errorImageResId); + } + } + }; + } + + public interface ImageListener { + + void onResponse(ImageContainer response, boolean isImmediate); + + void onError(ANError anError); + } + + public boolean isCached(String requestUrl, int maxWidth, int maxHeight) { + return isCached(requestUrl, maxWidth, maxHeight, ImageView.ScaleType.CENTER_INSIDE); + } + + public boolean isCached(String requestUrl, int maxWidth, int maxHeight, + ImageView.ScaleType scaleType) { + throwIfNotOnMainThread(); + + String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); + return mCache.getBitmap(cacheKey) != null; + } + + public ImageContainer get(String requestUrl, final ImageListener listener) { + return get(requestUrl, listener, 0, 0); + } + + + public ImageContainer get(String requestUrl, ImageListener imageListener, + int maxWidth, int maxHeight) { + return get(requestUrl, imageListener, maxWidth, maxHeight, + ImageView.ScaleType.CENTER_INSIDE); + } + + public ImageContainer get(String requestUrl, ImageListener imageListener, + int maxWidth, int maxHeight, ImageView.ScaleType scaleType) { + + throwIfNotOnMainThread(); + + final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType); + + Bitmap cachedBitmap = mCache.getBitmap(cacheKey); + if (cachedBitmap != null) { + ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); + imageListener.onResponse(container, true); + return container; + } + + ImageContainer imageContainer = + new ImageContainer(null, requestUrl, cacheKey, imageListener); + + imageListener.onResponse(imageContainer, true); + + BatchedImageRequest request = mInFlightRequests.get(cacheKey); + if (request != null) { + request.addContainer(imageContainer); + return imageContainer; + } + + ANRequest newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType, + cacheKey); + + mInFlightRequests.put(cacheKey, + new BatchedImageRequest(newRequest, imageContainer)); + return imageContainer; + } + + protected ANRequest makeImageRequest(String requestUrl, int maxWidth, int maxHeight, + ImageView.ScaleType scaleType, final String cacheKey) { + ANRequest ANRequest = AndroidNetworking.get(requestUrl) + .setTag("ImageRequestTag") + .setBitmapMaxHeight(maxHeight) + .setBitmapMaxWidth(maxWidth) + .setImageScaleType(scaleType) + .setBitmapConfig(Bitmap.Config.RGB_565) + .setBitmapOptions(mBitmapOptions) + .build(); + + ANRequest.getAsBitmap(new BitmapRequestListener() { + @Override + public void onResponse(Bitmap response) { + onGetImageSuccess(cacheKey, response); + } + + @Override + public void onError(ANError anError) { + onGetImageError(cacheKey, anError); + } + }); + + return ANRequest; + } + + public void setBitmapDecodeOptions(BitmapFactory.Options bitmapOptions) { + mBitmapOptions = bitmapOptions; + } + + public void setBatchedResponseDelay(int newBatchedResponseDelayMs) { + mBatchResponseDelayMs = newBatchedResponseDelayMs; + } + + + protected void onGetImageSuccess(String cacheKey, Bitmap response) { + mCache.putBitmap(cacheKey, response); + + BatchedImageRequest request = mInFlightRequests.remove(cacheKey); + + if (request != null) { + request.mResponseBitmap = response; + + batchResponse(cacheKey, request); + } + } + + protected void onGetImageError(String cacheKey, ANError anError) { + BatchedImageRequest request = mInFlightRequests.remove(cacheKey); + + if (request != null) { + request.setError(anError); + batchResponse(cacheKey, request); + } + } + + public class ImageContainer { + + private Bitmap mBitmap; + + private final ImageListener mListener; + + private final String mCacheKey; + + private final String mRequestUrl; + + public ImageContainer(Bitmap bitmap, String requestUrl, + String cacheKey, ImageListener listener) { + mBitmap = bitmap; + mRequestUrl = requestUrl; + mCacheKey = cacheKey; + mListener = listener; + } + + public void cancelRequest() { + if (mListener == null) { + return; + } + + BatchedImageRequest request = mInFlightRequests.get(mCacheKey); + if (request != null) { + boolean canceled = request.removeContainerAndCancelIfNecessary(this); + if (canceled) { + mInFlightRequests.remove(mCacheKey); + } + } else { + request = mBatchedResponses.get(mCacheKey); + if (request != null) { + request.removeContainerAndCancelIfNecessary(this); + if (request.mContainers.size() == 0) { + mBatchedResponses.remove(mCacheKey); + } + } + } + } + + public Bitmap getBitmap() { + return mBitmap; + } + + + public String getRequestUrl() { + return mRequestUrl; + } + } + + private class BatchedImageRequest { + + private final ANRequest mRequest; + + private Bitmap mResponseBitmap; + + private ANError mANError; + + private final LinkedList mContainers = new LinkedList(); + + public BatchedImageRequest(ANRequest request, ImageContainer container) { + mRequest = request; + mContainers.add(container); + } + + public void setError(ANError anError) { + mANError = anError; + } + + public ANError getError() { + return mANError; + } + + public void addContainer(ImageContainer container) { + mContainers.add(container); + } + + public boolean removeContainerAndCancelIfNecessary(ImageContainer container) { + mContainers.remove(container); + if (mContainers.size() == 0) { + mRequest.cancel(true); + if (mRequest.isCanceled()) { + mRequest.destroy(); + ANRequestQueue.getInstance().finish(mRequest); + } + return true; + } + return false; + } + } + + private void batchResponse(String cacheKey, BatchedImageRequest request) { + mBatchedResponses.put(cacheKey, request); + if (mRunnable == null) { + mRunnable = new Runnable() { + @Override + public void run() { + for (BatchedImageRequest bir : mBatchedResponses.values()) { + for (ImageContainer container : bir.mContainers) { + if (container.mListener == null) { + continue; + } + if (bir.getError() == null) { + container.mBitmap = bir.mResponseBitmap; + container.mListener.onResponse(container, false); + } else { + container.mListener.onError(bir.getError()); + } + } + } + mBatchedResponses.clear(); + mRunnable = null; + } + + }; + mHandler.postDelayed(mRunnable, mBatchResponseDelayMs); + } + } + + private void throwIfNotOnMainThread() { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw new IllegalStateException("ImageLoader must be invoked from the main thread."); + } + } + + private static String getCacheKey(String url, int maxWidth, int maxHeight, + ImageView.ScaleType scaleType) { + return new StringBuilder(url.length() + 12).append("#W").append(maxWidth) + .append("#H").append(maxHeight).append("#S").append(scaleType.ordinal()).append(url) + .toString(); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java b/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java new file mode 100644 index 0000000..b2cd8a6 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.Priority; +import com.androidnetworking.core.Core; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class ANRequestQueue { + + private final static String TAG = ANRequestQueue.class.getSimpleName(); + private final Set mCurrentRequests = new HashSet<>(); + private AtomicInteger mSequenceGenerator = new AtomicInteger(); + private static ANRequestQueue sInstance = null; + + public static void initialize() { + getInstance(); + } + + public static ANRequestQueue getInstance() { + if (sInstance == null) { + synchronized (ANRequestQueue.class) { + if (sInstance == null) { + sInstance = new ANRequestQueue(); + } + } + } + return sInstance; + } + + public interface RequestFilter { + boolean apply(ANRequest request); + } + + + private void cancel(RequestFilter filter, boolean forceCancel) { + synchronized (mCurrentRequests) { + try { + for (Iterator iterator = mCurrentRequests.iterator(); iterator.hasNext(); ) { + ANRequest request = iterator.next(); + if (filter.apply(request)) { + request.cancel(forceCancel); + if (request.isCanceled()) { + request.destroy(); + iterator.remove(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void cancelAll(boolean forceCancel) { + synchronized (mCurrentRequests) { + try { + for (Iterator iterator = mCurrentRequests.iterator(); iterator.hasNext(); ) { + ANRequest request = iterator.next(); + request.cancel(forceCancel); + if (request.isCanceled()) { + request.destroy(); + iterator.remove(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void cancelRequestWithGivenTag(final Object tag, final boolean forceCancel) { + try { + if (tag == null) { + return; + } + cancel(new RequestFilter() { + @Override + public boolean apply(ANRequest request) { + if (request.getTag() instanceof String && tag instanceof String) { + final String tempRequestTag = (String) request.getTag(); + final String tempTag = (String) tag; + return tempRequestTag.equals(tempTag); + } + return request.getTag().equals(tag); + } + }, forceCancel); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public int getSequenceNumber() { + return mSequenceGenerator.incrementAndGet(); + } + + public ANRequest addRequest(ANRequest request) { + synchronized (mCurrentRequests) { + try { + mCurrentRequests.add(request); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + request.setSequenceNumber(getSequenceNumber()); + if (request.getPriority() == Priority.IMMEDIATE) { + request.setFuture(Core.getInstance() + .getExecutorSupplier() + .forImmediateNetworkTasks() + .submit(new InternalRunnable(request))); + } else { + request.setFuture(Core.getInstance() + .getExecutorSupplier() + .forNetworkTasks() + .submit(new InternalRunnable(request))); + } + } catch (Exception e) { + e.printStackTrace(); + } + return request; + } + + public void finish(ANRequest request) { + synchronized (mCurrentRequests) { + try { + mCurrentRequests.remove(request); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java b/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java new file mode 100644 index 0000000..5951ef6 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.interfaces.DownloadProgressListener; +import com.androidnetworking.model.Progress; + +/** + * Created by amitshekhar on 24/05/16. + */ +public class DownloadProgressHandler extends Handler { + + private final DownloadProgressListener mDownloadProgressListenerWeakRef; + + public DownloadProgressHandler(DownloadProgressListener downloadProgressListener) { + super(Looper.getMainLooper()); + mDownloadProgressListenerWeakRef = downloadProgressListener; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case ANConstants.UPDATE: + if (mDownloadProgressListenerWeakRef != null) { + final Progress progress = (Progress) msg.obj; + mDownloadProgressListenerWeakRef.onProgress(progress.currentBytes, progress.totalBytes); + } + break; + default: + super.handleMessage(msg); + break; + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java b/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java new file mode 100644 index 0000000..ee7cfb0 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +/** + * Created by amitshekhar on 22/03/16. + */ + +import android.content.Context; +import android.net.TrafficStats; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ConnectionClassManager; +import com.androidnetworking.interceptors.HttpLoggingInterceptor; +import com.androidnetworking.interceptors.HttpLoggingInterceptor.Level; +import com.androidnetworking.error.ANError; +import com.androidnetworking.utils.Utils; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import static com.androidnetworking.common.Method.DELETE; +import static com.androidnetworking.common.Method.GET; +import static com.androidnetworking.common.Method.HEAD; +import static com.androidnetworking.common.Method.PATCH; +import static com.androidnetworking.common.Method.POST; +import static com.androidnetworking.common.Method.PUT; + +public final class InternalNetworking { + + private InternalNetworking() { + + } + + public static OkHttpClient sHttpClient = getClient(); + + public static String sUserAgent = null; + + public static Response performSimpleRequest(ANRequest request) throws ANError { + Request okHttpRequest; + Response okHttpResponse; + try { + Request.Builder builder = new Request.Builder().url(request.getUrl()); + addHeadersToRequestBuilder(builder, request); + RequestBody requestBody = null; + switch (request.getMethod()) { + case GET: { + builder = builder.get(); + break; + } + case POST: { + requestBody = request.getRequestBody(); + builder = builder.post(requestBody); + break; + } + case PUT: { + requestBody = request.getRequestBody(); + builder = builder.put(requestBody); + break; + } + case DELETE: { + requestBody = request.getRequestBody(); + builder = builder.delete(requestBody); + break; + } + case HEAD: { + builder = builder.head(); + break; + } + case PATCH: { + requestBody = request.getRequestBody(); + builder = builder.patch(requestBody); + break; + } + } + if (request.getCacheControl() != null) { + builder.cacheControl(request.getCacheControl()); + } + okHttpRequest = builder.build(); + + if (request.getOkHttpClient() != null) { + request.setCall(request.getOkHttpClient().newBuilder().cache(sHttpClient.cache()).build().newCall(okHttpRequest)); + } else { + request.setCall(sHttpClient.newCall(okHttpRequest)); + } + final long startTime = System.currentTimeMillis(); + final long startBytes = TrafficStats.getTotalRxBytes(); + okHttpResponse = request.getCall().execute(); + final long timeTaken = System.currentTimeMillis() - startTime; + if (okHttpResponse.cacheResponse() == null) { + final long finalBytes = TrafficStats.getTotalRxBytes(); + final long diffBytes; + if (startBytes == TrafficStats.UNSUPPORTED || finalBytes == TrafficStats.UNSUPPORTED) { + diffBytes = okHttpResponse.body().contentLength(); + } else { + diffBytes = finalBytes - startBytes; + } + ConnectionClassManager.getInstance().updateBandwidth(diffBytes, timeTaken); + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + (requestBody != null && + requestBody.contentLength() != 0) ? requestBody.contentLength() : -1, + okHttpResponse.body().contentLength(), false); + } else if (request.getAnalyticsListener() != null) { + if (okHttpResponse.networkResponse() == null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, 0, 0, true); + } else { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + (requestBody != null && requestBody.contentLength() != 0) ? requestBody.contentLength() : -1, + 0, true); + } + } + } catch (IOException ioe) { + throw new ANError(ioe); + } + return okHttpResponse; + } + + public static Response performDownloadRequest(final ANRequest request) throws ANError { + Request okHttpRequest; + Response okHttpResponse; + try { + Request.Builder builder = new Request.Builder().url(request.getUrl()); + addHeadersToRequestBuilder(builder, request); + builder = builder.get(); + if (request.getCacheControl() != null) { + builder.cacheControl(request.getCacheControl()); + } + okHttpRequest = builder.build(); + + OkHttpClient okHttpClient; + + if (request.getOkHttpClient() != null) { + okHttpClient = request.getOkHttpClient().newBuilder().cache(sHttpClient.cache()) + .addNetworkInterceptor(new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ResponseProgressBody(originalResponse.body(), + request.getDownloadProgressListener())) + .build(); + } + }).build(); + } else { + okHttpClient = sHttpClient.newBuilder() + .addNetworkInterceptor(new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ResponseProgressBody(originalResponse.body(), + request.getDownloadProgressListener())) + .build(); + } + }).build(); + } + request.setCall(okHttpClient.newCall(okHttpRequest)); + final long startTime = System.currentTimeMillis(); + final long startBytes = TrafficStats.getTotalRxBytes(); + okHttpResponse = request.getCall().execute(); + Utils.saveFile(okHttpResponse, request.getDirPath(), request.getFileName()); + final long timeTaken = System.currentTimeMillis() - startTime; + if (okHttpResponse.cacheResponse() == null) { + final long finalBytes = TrafficStats.getTotalRxBytes(); + final long diffBytes; + if (startBytes == TrafficStats.UNSUPPORTED || finalBytes == TrafficStats.UNSUPPORTED) { + diffBytes = okHttpResponse.body().contentLength(); + } else { + diffBytes = finalBytes - startBytes; + } + ConnectionClassManager.getInstance().updateBandwidth(diffBytes, timeTaken); + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, -1, + okHttpResponse.body().contentLength(), false); + } else if (request.getAnalyticsListener() != null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, -1, 0, true); + } + } catch (IOException ioe) { + try { + File destinationFile = new File(request.getDirPath() + File.separator + request.getFileName()); + if (destinationFile.exists()) { + destinationFile.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + throw new ANError(ioe); + } + return okHttpResponse; + } + + + public static Response performUploadRequest(ANRequest request) throws ANError { + Request okHttpRequest; + Response okHttpResponse; + try { + Request.Builder builder = new Request.Builder().url(request.getUrl()); + addHeadersToRequestBuilder(builder, request); + final RequestBody requestBody = request.getMultiPartRequestBody(); + final long requestBodyLength = requestBody.contentLength(); + builder = builder.post(new RequestProgressBody(requestBody, request.getUploadProgressListener())); + if (request.getCacheControl() != null) { + builder.cacheControl(request.getCacheControl()); + } + okHttpRequest = builder.build(); + if (request.getOkHttpClient() != null) { + request.setCall(request.getOkHttpClient() + .newBuilder() + .cache(sHttpClient.cache()) + .build() + .newCall(okHttpRequest)); + } else { + request.setCall(sHttpClient.newCall(okHttpRequest)); + } + final long startTime = System.currentTimeMillis(); + okHttpResponse = request.getCall().execute(); + final long timeTaken = System.currentTimeMillis() - startTime; + if (request.getAnalyticsListener() != null) { + if (okHttpResponse.cacheResponse() == null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + requestBodyLength, okHttpResponse.body().contentLength(), false); + } else { + if (okHttpResponse.networkResponse() == null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, 0, 0, true); + } else { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + requestBodyLength != 0 ? requestBodyLength : -1, 0, true); + } + } + } + } catch (IOException ioe) { + throw new ANError(ioe); + } + return okHttpResponse; + } + + public static OkHttpClient getClient() { + if (sHttpClient == null) { + return getDefaultClient(); + } + return sHttpClient; + } + + public static void addHeadersToRequestBuilder(Request.Builder builder, ANRequest request) { + if (request.getUserAgent() != null) { + builder.addHeader(ANConstants.USER_AGENT, request.getUserAgent()); + } else if (sUserAgent != null) { + request.setUserAgent(sUserAgent); + builder.addHeader(ANConstants.USER_AGENT, sUserAgent); + } + Headers requestHeaders = request.getHeaders(); + if (requestHeaders != null) { + builder.headers(requestHeaders); + if (request.getUserAgent() != null && !requestHeaders.names().contains(ANConstants.USER_AGENT)) { + builder.addHeader(ANConstants.USER_AGENT, request.getUserAgent()); + } + } + } + + public static OkHttpClient getDefaultClient() { + return new OkHttpClient().newBuilder() + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .build(); + } + + public static void setClientWithCache(Context context) { + sHttpClient = new OkHttpClient().newBuilder() + .cache(Utils.getCache(context, ANConstants.MAX_CACHE_SIZE, ANConstants.CACHE_DIR_NAME)) + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .build(); + } + + public static void setUserAgent(String userAgent) { + sUserAgent = userAgent; + } + + public static void setClient(OkHttpClient okHttpClient) { + sHttpClient = okHttpClient; + } + + public static void enableLogging(Level level) { + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); + logging.setLevel(level); + sHttpClient = getClient() + .newBuilder() + .addInterceptor(logging) + .build(); + } + +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java b/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java new file mode 100644 index 0000000..b784b9c --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.common.Priority; +import com.androidnetworking.common.ResponseType; +import com.androidnetworking.core.Core; +import com.androidnetworking.error.ANError; +import com.androidnetworking.utils.SourceCloseUtil; +import com.androidnetworking.utils.Utils; + +import okhttp3.Response; + +import static com.androidnetworking.common.RequestType.DOWNLOAD; +import static com.androidnetworking.common.RequestType.MULTIPART; +import static com.androidnetworking.common.RequestType.SIMPLE; + +/** + * Created by amitshekhar on 22/03/16. + */ +public class InternalRunnable implements Runnable { + + private final Priority priority; + public final int sequence; + public final ANRequest request; + + public InternalRunnable(ANRequest request) { + this.request = request; + this.sequence = request.getSequenceNumber(); + this.priority = request.getPriority(); + } + + @Override + public void run() { + switch (request.getRequestType()) { + case SIMPLE: + executeSimpleRequest(); + break; + case DOWNLOAD: + executeDownloadRequest(); + break; + case MULTIPART: + executeUploadRequest(); + break; + } + } + + private void executeSimpleRequest() { + Response okHttpResponse = null; + try { + okHttpResponse = InternalNetworking.performSimpleRequest(request); + + if (okHttpResponse == null) { + deliverError(request, Utils.getErrorForConnection(new ANError())); + return; + } + + if (request.getResponseAs() == ResponseType.OK_HTTP_RESPONSE) { + request.deliverOkHttpResponse(okHttpResponse); + return; + } + if (okHttpResponse.code() >= 400) { + deliverError(request, Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + return; + } + + ANResponse response = request.parseResponse(okHttpResponse); + if (!response.isSuccess()) { + deliverError(request, response.getError()); + return; + } + response.setOkHttpResponse(okHttpResponse); + request.deliverResponse(response); + } catch (Exception e) { + deliverError(request, Utils.getErrorForConnection(new ANError(e))); + } finally { + SourceCloseUtil.close(okHttpResponse, request); + } + } + + private void executeDownloadRequest() { + Response okHttpResponse; + try { + okHttpResponse = InternalNetworking.performDownloadRequest(request); + if (okHttpResponse == null) { + deliverError(request, Utils.getErrorForConnection(new ANError())); + return; + } + if (okHttpResponse.code() >= 400) { + deliverError(request, Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + return; + } + request.updateDownloadCompletion(); + } catch (Exception e) { + deliverError(request, Utils.getErrorForConnection(new ANError(e))); + } + } + + private void executeUploadRequest() { + Response okHttpResponse = null; + try { + okHttpResponse = InternalNetworking.performUploadRequest(request); + + if (okHttpResponse == null) { + deliverError(request, Utils.getErrorForConnection(new ANError())); + return; + } + + if (request.getResponseAs() == ResponseType.OK_HTTP_RESPONSE) { + request.deliverOkHttpResponse(okHttpResponse); + return; + } + + if (okHttpResponse.code() >= 400) { + deliverError(request, Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + return; + } + ANResponse response = request.parseResponse(okHttpResponse); + if (!response.isSuccess()) { + deliverError(request, response.getError()); + return; + } + response.setOkHttpResponse(okHttpResponse); + request.deliverResponse(response); + } catch (Exception e) { + deliverError(request, Utils.getErrorForConnection(new ANError(e))); + } finally { + SourceCloseUtil.close(okHttpResponse, request); + } + } + + public Priority getPriority() { + return priority; + } + + private void deliverError(final ANRequest request, final ANError anError) { + Core.getInstance().getExecutorSupplier().forMainThreadTasks().execute(new Runnable() { + public void run() { + request.deliverError(anError); + request.finish(); + } + }); + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java b/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java new file mode 100644 index 0000000..7e4f61c --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.interfaces.UploadProgressListener; +import com.androidnetworking.model.Progress; + +import java.io.IOException; + +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okio.Buffer; +import okio.BufferedSink; +import okio.ForwardingSink; +import okio.Okio; +import okio.Sink; + +/** + * Created by amitshekhar on 21/04/16. + */ +public class RequestProgressBody extends RequestBody { + private final RequestBody requestBody; + private BufferedSink bufferedSink; + private UploadProgressHandler uploadProgressHandler; + + public RequestProgressBody(RequestBody requestBody, UploadProgressListener uploadProgressListener) { + this.requestBody = requestBody; + if (uploadProgressListener != null) { + this.uploadProgressHandler = new UploadProgressHandler(uploadProgressListener); + } + } + + public MediaType contentType() { + return requestBody.contentType(); + } + + @Override + public long contentLength() throws IOException { + return requestBody.contentLength(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + if (bufferedSink == null) { + bufferedSink = Okio.buffer(sink(sink)); + } + requestBody.writeTo(bufferedSink); + bufferedSink.flush(); + } + + private Sink sink(Sink sink) { + return new ForwardingSink(sink) { + long bytesWritten = 0L; + long contentLength = 0L; + + @Override + public void write(Buffer source, long byteCount) throws IOException { + super.write(source, byteCount); + if (contentLength == 0) { + contentLength = contentLength(); + } + bytesWritten += byteCount; + if (uploadProgressHandler != null) { + uploadProgressHandler.obtainMessage(ANConstants.UPDATE, + new Progress(bytesWritten, contentLength)).sendToTarget(); + } + } + }; + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java b/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java new file mode 100644 index 0000000..f1dfc97 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.interfaces.DownloadProgressListener; +import com.androidnetworking.model.Progress; + +import java.io.IOException; + +import okhttp3.MediaType; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; +import okio.ForwardingSource; +import okio.Okio; +import okio.Source; + +/** + * Created by amitshekhar on 24/05/16. + */ +public class ResponseProgressBody extends ResponseBody { + + private final ResponseBody mResponseBody; + private BufferedSource bufferedSource; + private DownloadProgressHandler downloadProgressHandler; + + public ResponseProgressBody(ResponseBody responseBody, DownloadProgressListener downloadProgressListener) { + this.mResponseBody = responseBody; + if (downloadProgressListener != null) { + this.downloadProgressHandler = new DownloadProgressHandler(downloadProgressListener); + } + } + + @Override + public MediaType contentType() { + return mResponseBody.contentType(); + } + + @Override + public long contentLength() { + return mResponseBody.contentLength(); + } + + @Override + public BufferedSource source() { + if (bufferedSource == null) { + bufferedSource = Okio.buffer(source(mResponseBody.source())); + } + return bufferedSource; + } + + private Source source(Source source) { + + return new ForwardingSource(source) { + + long totalBytesRead; + + @Override + public long read(Buffer sink, long byteCount) throws IOException { + long bytesRead = super.read(sink, byteCount); + totalBytesRead += ((bytesRead != -1) ? bytesRead : 0); + if (downloadProgressHandler != null) { + downloadProgressHandler + .obtainMessage(ANConstants.UPDATE, + new Progress(totalBytesRead, mResponseBody.contentLength())) + .sendToTarget(); + } + return bytesRead; + } + }; + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java b/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java new file mode 100644 index 0000000..9dd8101 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java @@ -0,0 +1,143 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.internal; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.common.ResponseType; +import com.androidnetworking.error.ANError; +import com.androidnetworking.utils.SourceCloseUtil; +import com.androidnetworking.utils.Utils; + +import okhttp3.Response; + +import static com.androidnetworking.common.RequestType.DOWNLOAD; +import static com.androidnetworking.common.RequestType.MULTIPART; +import static com.androidnetworking.common.RequestType.SIMPLE; + +/** + * Created by amitshekhar on 14/09/16. + */ +@SuppressWarnings("unchecked") +public final class SynchronousCall { + + private SynchronousCall() { + + } + + public static ANResponse execute(ANRequest request) { + switch (request.getRequestType()) { + case SIMPLE: + return executeSimpleRequest(request); + case DOWNLOAD: + return executeDownloadRequest(request); + case MULTIPART: + return executeUploadRequest(request); + } + return new ANResponse<>(new ANError()); + } + + private static ANResponse executeSimpleRequest(ANRequest request) { + Response okHttpResponse = null; + try { + okHttpResponse = InternalNetworking.performSimpleRequest(request); + if (okHttpResponse == null) { + return new ANResponse<>(Utils.getErrorForConnection(new ANError())); + } + + if (request.getResponseAs() == ResponseType.OK_HTTP_RESPONSE) { + ANResponse response = new ANResponse(okHttpResponse); + response.setOkHttpResponse(okHttpResponse); + return response; + } + if (okHttpResponse.code() >= 400) { + ANResponse response = new ANResponse<>(Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + response.setOkHttpResponse(okHttpResponse); + return response; + } + ANResponse response = request.parseResponse(okHttpResponse); + response.setOkHttpResponse(okHttpResponse); + return response; + } catch (ANError se) { + return new ANResponse<>(Utils.getErrorForConnection(new ANError(se))); + } catch (Exception e) { + return new ANResponse<>(Utils.getErrorForNetworkOnMainThreadOrConnection(e)); + } finally { + SourceCloseUtil.close(okHttpResponse, request); + } + } + + private static ANResponse executeDownloadRequest(ANRequest request) { + Response okHttpResponse; + try { + okHttpResponse = InternalNetworking.performDownloadRequest(request); + if (okHttpResponse == null) { + return new ANResponse<>(Utils.getErrorForConnection(new ANError())); + } + if (okHttpResponse.code() >= 400) { + ANResponse response = new ANResponse<>(Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + response.setOkHttpResponse(okHttpResponse); + return response; + } + ANResponse response = new ANResponse(ANConstants.SUCCESS); + response.setOkHttpResponse(okHttpResponse); + return response; + } catch (ANError se) { + return new ANResponse<>(Utils.getErrorForConnection(new ANError(se))); + } catch (Exception e) { + return new ANResponse<>(Utils.getErrorForNetworkOnMainThreadOrConnection(e)); + } + } + + private static ANResponse executeUploadRequest(ANRequest request) { + Response okHttpResponse = null; + try { + okHttpResponse = InternalNetworking.performUploadRequest(request); + + if (okHttpResponse == null) { + return new ANResponse<>(Utils.getErrorForConnection(new ANError())); + } + + if (request.getResponseAs() == ResponseType.OK_HTTP_RESPONSE) { + ANResponse response = new ANResponse(okHttpResponse); + response.setOkHttpResponse(okHttpResponse); + return response; + } + if (okHttpResponse.code() >= 400) { + ANResponse response = new ANResponse<>(Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + response.setOkHttpResponse(okHttpResponse); + return response; + } + ANResponse response = request.parseResponse(okHttpResponse); + response.setOkHttpResponse(okHttpResponse); + return response; + } catch (ANError se) { + return new ANResponse<>(Utils.getErrorForConnection(se)); + } catch (Exception e) { + return new ANResponse<>(Utils.getErrorForNetworkOnMainThreadOrConnection(e)); + } finally { + SourceCloseUtil.close(okHttpResponse, request); + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java b/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java new file mode 100644 index 0000000..e19f7f0 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.internal; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.interfaces.UploadProgressListener; +import com.androidnetworking.model.Progress; + +/** + * Created by amitshekhar on 24/05/16. + */ +public class UploadProgressHandler extends Handler { + + private final UploadProgressListener mUploadProgressListenerWeakRef; + + public UploadProgressHandler(UploadProgressListener uploadProgressListener) { + super(Looper.getMainLooper()); + mUploadProgressListenerWeakRef = uploadProgressListener; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case ANConstants.UPDATE: + if (mUploadProgressListenerWeakRef != null) { + final Progress progress = (Progress) msg.obj; + mUploadProgressListenerWeakRef.onProgress(progress.currentBytes, progress.totalBytes); + } + break; + default: + super.handleMessage(msg); + break; + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/model/Progress.java b/android-networking/src/main/java/com/androidnetworking/model/Progress.java new file mode 100644 index 0000000..d9c615d --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/model/Progress.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.model; + +import java.io.Serializable; + +/** + * Created by amitshekhar on 24/05/16. + */ + +public class Progress implements Serializable { + + public long currentBytes; + public long totalBytes; + + public Progress(long currentBytes, long totalBytes) { + this.currentBytes = currentBytes; + this.totalBytes = totalBytes; + } + +} \ No newline at end of file diff --git a/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java b/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java new file mode 100644 index 0000000..ec6acf4 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java @@ -0,0 +1,48 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.utils; + +import com.androidnetworking.gsonparserfactory.GsonParserFactory; +import com.androidnetworking.interfaces.Parser; +import com.google.gson.Gson; + +/** + * Created by amitshekhar on 15/09/16. + */ +public class ParseUtil { + + private static Parser.Factory mParserFactory; + + public static void setParserFactory(Parser.Factory parserFactory) { + mParserFactory = parserFactory; + } + + public static Parser.Factory getParserFactory() { + if (mParserFactory == null) { + mParserFactory = new GsonParserFactory(new Gson()); + } + return mParserFactory; + } + + public static void shutDown() { + mParserFactory = null; + } + +} diff --git a/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java b/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java new file mode 100644 index 0000000..eaf268a --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java @@ -0,0 +1,46 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.androidnetworking.utils; + +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ResponseType; + +import okhttp3.Response; + +/** + * Created by amitshekhar on 15/09/16. + */ +public final class SourceCloseUtil { + + private SourceCloseUtil() { + } + + public static void close(Response response, ANRequest request) { + if (request.getResponseAs() != ResponseType.OK_HTTP_RESPONSE && + response != null && response.body() != null && + response.body().source() != null) { + try { + response.body().source().close(); + } catch (Exception ignore) { + + } + } + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/utils/Utils.java b/android-networking/src/main/java/com/androidnetworking/utils/Utils.java new file mode 100644 index 0000000..416e978 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/utils/Utils.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Build; +import android.os.NetworkOnMainThreadException; +import android.widget.ImageView; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.core.Core; +import com.androidnetworking.error.ANError; +import com.androidnetworking.interfaces.AnalyticsListener; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.FileNameMap; +import java.net.URLConnection; + +import okhttp3.Cache; +import okhttp3.Response; +import okio.Okio; + +/** + * Created by amitshekhar on 25/03/16. + */ +public class Utils { + + public static File getDiskCacheDir(Context context, String uniqueName) { + return new File(context.getCacheDir(), uniqueName); + } + + public static Cache getCache(Context context, int maxCacheSize, String uniqueName) { + return new Cache(getDiskCacheDir(context, uniqueName), maxCacheSize); + } + + public static String getMimeType(String path) { + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + String contentTypeFor = fileNameMap.getContentTypeFor(path); + if (contentTypeFor == null) { + contentTypeFor = "application/octet-stream"; + } + return contentTypeFor; + } + + public static ANResponse decodeBitmap(Response response, int maxWidth, + int maxHeight, Bitmap.Config decodeConfig, + ImageView.ScaleType scaleType) { + return decodeBitmap(response, maxWidth, maxHeight, decodeConfig, + new BitmapFactory.Options(), scaleType); + } + + public static ANResponse decodeBitmap(Response response, int maxWidth, + int maxHeight, Bitmap.Config decodeConfig, + BitmapFactory.Options decodeOptions, + ImageView.ScaleType scaleType) { + byte[] data = new byte[0]; + try { + data = Okio.buffer(response.body().source()).readByteArray(); + } catch (IOException e) { + e.printStackTrace(); + } + Bitmap bitmap = null; + if (maxWidth == 0 && maxHeight == 0) { + decodeOptions.inPreferredConfig = decodeConfig; + bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); + } else { + decodeOptions.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); + int actualWidth = decodeOptions.outWidth; + int actualHeight = decodeOptions.outHeight; + + int desiredWidth = getResizedDimension(maxWidth, maxHeight, + actualWidth, actualHeight, scaleType); + int desiredHeight = getResizedDimension(maxHeight, maxWidth, + actualHeight, actualWidth, scaleType); + + decodeOptions.inJustDecodeBounds = false; + decodeOptions.inSampleSize = + findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight); + Bitmap tempBitmap = + BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); + + if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || + tempBitmap.getHeight() > desiredHeight)) { + bitmap = Bitmap.createScaledBitmap(tempBitmap, + desiredWidth, desiredHeight, true); + tempBitmap.recycle(); + } else { + bitmap = tempBitmap; + } + } + + if (bitmap == null) { + return ANResponse.failed(Utils.getErrorForParse(new ANError(response))); + } else { + return ANResponse.success(bitmap); + } + } + + private static int getResizedDimension(int maxPrimary, int maxSecondary, + int actualPrimary, int actualSecondary, + ImageView.ScaleType scaleType) { + + if ((maxPrimary == 0) && (maxSecondary == 0)) { + return actualPrimary; + } + + if (scaleType == ImageView.ScaleType.FIT_XY) { + if (maxPrimary == 0) { + return actualPrimary; + } + return maxPrimary; + } + + if (maxPrimary == 0) { + double ratio = (double) maxSecondary / (double) actualSecondary; + return (int) (actualPrimary * ratio); + } + + if (maxSecondary == 0) { + return maxPrimary; + } + + double ratio = (double) actualSecondary / (double) actualPrimary; + int resized = maxPrimary; + + if (scaleType == ImageView.ScaleType.CENTER_CROP) { + if ((resized * ratio) < maxSecondary) { + resized = (int) (maxSecondary / ratio); + } + return resized; + } + + if ((resized * ratio) > maxSecondary) { + resized = (int) (maxSecondary / ratio); + } + return resized; + } + + public static int findBestSampleSize(int actualWidth, int actualHeight, + int desiredWidth, int desiredHeight) { + double wr = (double) actualWidth / desiredWidth; + double hr = (double) actualHeight / desiredHeight; + double ratio = Math.min(wr, hr); + float n = 1.0f; + while ((n * 2) <= ratio) { + n *= 2; + } + return (int) n; + } + + public static void saveFile(Response response, String dirPath, + String fileName) throws IOException { + InputStream is = null; + byte[] buf = new byte[2048]; + int len; + FileOutputStream fos = null; + try { + is = response.body().byteStream(); + File dir = new File(dirPath); + if (!dir.exists()) { + dir.mkdirs(); + } + File file = new File(dir, fileName); + fos = new FileOutputStream(file); + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + } + fos.flush(); + } finally { + try { + if (is != null) is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (fos != null) fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static void sendAnalytics(final AnalyticsListener analyticsListener, + final long timeTakenInMillis, final long bytesSent, + final long bytesReceived, final boolean isFromCache) { + Core.getInstance().getExecutorSupplier().forMainThreadTasks().execute(new Runnable() { + @Override + public void run() { + if (analyticsListener != null) { + analyticsListener.onReceived(timeTakenInMillis, bytesSent, bytesReceived, + isFromCache); + } + } + }); + } + + public static ANError getErrorForConnection(ANError error) { + error.setErrorDetail(ANConstants.CONNECTION_ERROR); + error.setErrorCode(0); + return error; + } + + + public static ANError getErrorForServerResponse(ANError error, ANRequest request, int code) { + error = request.parseNetworkError(error); + error.setErrorCode(code); + error.setErrorDetail(ANConstants.RESPONSE_FROM_SERVER_ERROR); + return error; + } + + public static ANError getErrorForParse(ANError error) { + error.setErrorCode(0); + error.setErrorDetail(ANConstants.PARSE_ERROR); + return error; + } + + public static ANError getErrorForNetworkOnMainThreadOrConnection(Exception e) { + ANError error = new ANError(e); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB + && e instanceof NetworkOnMainThreadException) { + error.setErrorDetail(ANConstants.NETWORK_ON_MAIN_THREAD_ERROR); + } else { + error.setErrorDetail(ANConstants.CONNECTION_ERROR); + } + error.setErrorCode(0); + return error; + } +} diff --git a/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java b/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java new file mode 100644 index 0000000..bef56a5 --- /dev/null +++ b/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.androidnetworking.error.ANError; +import com.androidnetworking.internal.ANImageLoader; + +/** + * Created by amitshekhar on 23/03/16. + */ +public class ANImageView extends ImageView { + + private String mUrl; + + private int mDefaultImageId; + + private int mErrorImageId; + + private ANImageLoader.ImageContainer mImageContainer; + + public ANImageView(Context context) { + this(context, null); + } + + public ANImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ANImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setImageUrl(String url) { + mUrl = url; + loadImageIfNecessary(false); + } + + public void setDefaultImageResId(int defaultImage) { + mDefaultImageId = defaultImage; + } + + public void setErrorImageResId(int errorImage) { + mErrorImageId = errorImage; + } + + void loadImageIfNecessary(final boolean isInLayoutPass) { + int width = getWidth(); + int height = getHeight(); + ScaleType scaleType = getScaleType(); + + boolean wrapWidth = false, wrapHeight = false; + if (getLayoutParams() != null) { + wrapWidth = getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT; + wrapHeight = getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT; + } + + boolean isFullyWrapContent = wrapWidth && wrapHeight; + if (width == 0 && height == 0 && !isFullyWrapContent) { + return; + } + + if (TextUtils.isEmpty(mUrl)) { + if (mImageContainer != null) { + mImageContainer.cancelRequest(); + mImageContainer = null; + } + setDefaultImageOrNull(); + return; + } + + if (mImageContainer != null && mImageContainer.getRequestUrl() != null) { + if (mImageContainer.getRequestUrl().equals(mUrl)) { + return; + } else { + mImageContainer.cancelRequest(); + setDefaultImageOrNull(); + } + } + + int maxWidth = wrapWidth ? 0 : width; + int maxHeight = wrapHeight ? 0 : height; + + ANImageLoader.ImageContainer newContainer = ANImageLoader.getInstance().get(mUrl, + new ANImageLoader.ImageListener() { + @Override + public void onResponse(final ANImageLoader.ImageContainer response, + boolean isImmediate) { + if (isImmediate && isInLayoutPass) { + post(new Runnable() { + @Override + public void run() { + onResponse(response, false); + } + }); + return; + } + + if (response.getBitmap() != null) { + setImageBitmap(response.getBitmap()); + } else if (mDefaultImageId != 0) { + setImageResource(mDefaultImageId); + } + } + + @Override + public void onError(ANError error) { + if (mErrorImageId != 0) { + setImageResource(mErrorImageId); + } + } + }, maxWidth, maxHeight, scaleType); + + mImageContainer = newContainer; + } + + private void setDefaultImageOrNull() { + if (mDefaultImageId != 0) { + setImageResource(mDefaultImageId); + } else { + setImageBitmap(null); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + loadImageIfNecessary(true); + } + + @Override + protected void onDetachedFromWindow() { + if (mImageContainer != null) { + mImageContainer.cancelRequest(); + setImageBitmap(null); + mImageContainer = null; + } + super.onDetachedFromWindow(); + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + invalidate(); + } + +} diff --git a/android-networking/src/main/res/values/strings.xml b/android-networking/src/main/res/values/strings.xml new file mode 100644 index 0000000..66ca996 --- /dev/null +++ b/android-networking/src/main/res/values/strings.xml @@ -0,0 +1,20 @@ + + + + Android Networking + diff --git a/android-networking/src/test/java/com/androidnetworking/ExampleUnitTest.java b/android-networking/src/test/java/com/androidnetworking/ExampleUnitTest.java new file mode 100644 index 0000000..bbc8754 --- /dev/null +++ b/android-networking/src/test/java/com/androidnetworking/ExampleUnitTest.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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.androidnetworking; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/android-networking/upload.gradle b/android-networking/upload.gradle new file mode 100755 index 0000000..7580a50 --- /dev/null +++ b/android-networking/upload.gradle @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Amit Shekhar + * Copyright (C) 2011 Android Open Source Project + * + * 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. + */ + +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: "com.jfrog.bintray" + +def siteUrl = 'https://github.com/amitshekhariitbhu/Fast-Android-Networking' +def gitUrl = 'https://github.com/amitshekhariitbhu/Fast-Android-Networking.git' + +group = "com.amitshekhar.android" +version = '1.0.0' + +install { + repositories.mavenInstaller { + pom.project { + packaging 'aar' + + name 'Fast Android Networking' + description 'Fast Android Networking is a powerful library for doing any type of networking in Android applications' + + url siteUrl + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id 'amitshekhariitbhu' + name 'Amit Shekhar' + email 'amit.shekhar.iitbhu@gmail.com' + } + } + + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } +} + +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' +} + +task javadoc(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + classpath += configurations.compile +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} +artifacts { + archives javadocJar + archives sourcesJar +} + +if (project.rootProject.file("local.properties").exists()) { + Properties properties = new Properties() + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + + bintray { + user = properties.getProperty("bintray.user") + key = properties.getProperty("bintray.apikey") + + configurations = ['archives'] + dryRun = false + + pkg { + repo = "maven" + name = "android-networking" + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = ["Apache-2.0"] + publish = true + } + } +} diff --git a/app/build.gradle b/app/build.gradle index 62fe87b..7f9dfae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,5 +26,4 @@ dependencies { compile 'com.android.support:recyclerview-v7:25.1.0' compile 'io.reactivex.rxjava2:rxjava:2.1.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' - compile 'com.amitshekhar.android:rx2-android-networking:1.0.0' } diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png old mode 100644 new mode 100755 index cde69bcccec65160d92116f20ffce4fce0b5245c..a3753ae3643b06e08c8b494e7a2e5a4c41397f98 GIT binary patch literal 4186 zcmV-g5T);lP)^r-x`^K`cAcCi2BuYhsMnumuXEgB-<5hB=;S3x`D;h1WOD=U* z5)<r=0Yoqn2g8f9TMmmztWI21Xjqh%UBg&z{QJvuFQ@uIr06O)CW4BmL+U z|K1cr^x3w(ZU6rLw>332bqqJ&VF5k!%rk}8UVH5yT`t!brud}CG(5|)UVq_*7p`Bi zVnx@Ck?3?A~G^eWaq$`;cB+5^ zt*xzhRaaMk?@XBJSjX7i-My})q~uN@a;kvxT3TA}s;Q~@?pRNLCLEUm^erGfB>)K_ zP8f%#jaY4r8|x_rNWvKj&_u(U5`Y{iwrwNgCSq?l;=>;B7-&t!X!V6?x{idC3uq!> zO*$aQY9t)HHxBFGM*FXQ=;1hM8diZ9`??0~ThB!=37{J~nxU&Ln%rf4p-mbf$73m;V$;0yV9lD zU|^>koF*L5$J{9sbF8kgg2OZWI2=o{*OqVumH<7|+8)aB1YrSOS?(fTYQ?%wYSQ`#tZ%^x5GO$ZmP06iG$NR-bitk#4ucBZ~ zmNf2woH{3!N|ES`z&)FJ=j9HbHEjh!!g1cxl4J~;p{2zaIayOf?WbkpjkB)@4PU^Z z@Ro&$S6k8FlbV)BN(cogAs{Y)!{;J@RAl zZ3&?QuY^;iL8Yz{%(!B@4A2xPrzCKpDMZqOk|M2cDM-?y42^;{f5X0VFXffREc{&U zsNHQ`0Xeb9e5D1~1FzG1WPr5^OI6A8%FCEjsV=;h29t>&>CZy_+cq>jW@s;9v;* z#ZL0J_TlYH;ECH9mQZDa3|3ASlddHp$*pPVxc{Mn0op=Yfj|Rutm%`Ea}4*(>c>kW-Zp-YPvQM|6`DcdSHO;N~aa<1atm&24L!a{lFY zxZNI=(H!d>%8JGvkaUM|dx%|M+sK~|hPlDeDbEcx5F8l?7~jwuOIrVmVD0 zos$JLR4f`dKu!%5KirLbZ3um0*#<_sU6_6ZUtT&APotN3S zv4i(5n`MTstVN~vOfe{3Oc*-8`xa1n(|K7yW0g;Hb?#U=#>S8#O$lyRdu7I30-}}}zcBlG@#>_Bn$)heG94h z%6ZxNGhB8VPS42}si_nPHn;FUYhI!+6h-(AB4LXJ8Vhfz;pT^yDt8{72qw&eB%ow6 zNi-Ve*h~8e{d5oKcEnX7=M;yky^s~K2F5=&QNHHl(*l%L50WWbUq8%?_rJ=~{XOZP zEK^+@K@T^sy^Oh^otZ5qPG+s+WazeCj@TCh#~SW8kTWEi`OP$Lu(1}L{3CpJOhHC!y!6oDuRL`A(Kj2r{a=2=G+$_ksqE04}Rul>K zqd&Bbk`0}iOqOXiGR30o!HkvXk$>CyxMhF7uLom(IhtHy9btvSajj%5$$?GH^mg=O zx&-|#{d8{bBJ@E&dWnYxtD300xQ0Zx$?VJO@OVAL_G9A?NL|%TERt5#zx@zp_wK;g zolHYgF(}<;sBAW?5bw_}$6YxM`xiTLpI?FNx<&=)WSJ&6Yst(RkH+cQcZ|Kid5^Xi z+X?q3p~S_kJ7!T-QOtW!9pc=Z8@TZL`PpK0!kbm+gwEjAz~gaZktp%U-=gx#7L0`K zosL)1rY%%`Vqaa0=R1qw`2%=(h0S3FNd8A|ofQew1@^2U(a#h!?f*K^LrKiKAo|U7@O^O(Mv-52?*03_ zX#2@l;v0_;kEN7YpClu@X5`kSEtN%q?a`^bbru(|UPM7*!3j#iqyZWnu$4v>i_y2U zg|Z*KM?p&rO`4FDDl+R@PMu_X4dNv(0-XtLOJK=XWnmfaTjt?9zZ_BEA{>rzi3yqCZfbVDQfxiT(%@Dj?Z%arvv74)RY9fPli(<7+`#8gTZkg;f# z@a}f6oMfd#;$4Q5w^-YFZvKJqGsl0HSspR;iDq3nG0{BCY)-+G8a9 zOa({@az35BE2lH(n+qwcEzhQvXj2l#C)9;lV29q$r9f%L-0b zQ|t6nGR+i`k%2JrEe9z3V;jK_qbkEWpyU!zT2wpU;Hu^2oRts>#c3tfzB-6=;&~_wK2}u@`N{m0;jsAKE{x?2i+P)~ho)nslJvqXD zu9oC15jom+%B_*8^dK%SA#imKMe{2OqHAQqV;}Ki%an@swA(vh(ItOug{we z$hoT+qt%%v1yHX0a5~?`xX&seGVL2w}Cix38_PuD*XPPy6`SuU~)tvSrI2bGzO0Vct*O%QVf% z)~#E=y=2Lf-vQB~COF)4NZu7IR@AOtyY{zrb#A;^4u9@85m*-D{qE?zuhk zv5`#ccS?Zd&hjp}!nt$jR;^mK>hkL9>X{yoN8VO=#=cC`jJLP9x2{{a?#1ofw;#^H zk+(Yz`5Ng_Kl#0cB>!&<@+~b$2JDfJo2mdEy-wcVC?CO;&#B7KCq4$5nZal$>O6O% z9-Ww~vmfQSoZB27QFGYCMhnRK5oiBXJ#Lg^ANSoHOF5~<3?9LmI?-__IoKj5?1X39 kiOyQk2v_VZpb-H5KlLXx-#VB(z5oCK07*qoM6N<$g638r*#H0l literal 3418 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 VFwL6zQVak9002ovPDHLkV1mDq3IYHC diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png old mode 100644 new mode 100755 index bfa42f0e7b91d006d22352c9ff2f134e504e3c1d..b82cd0fa8e544715ac87cb27fab5404545d9d122 GIT binary patch literal 6040 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 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png old mode 100644 new mode 100755 index 324e72cdd7480cb983fa1bcc7ce686e51ef87fe7..692e2fd8a50004294721cb8aa3c1f483048349a6 GIT binary patch literal 11516 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 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png old mode 100644 new mode 100755 index aee44e138434630332d88b1680f33c4b24c70ab3..34cb12dbf11735ca705522eaa9b2d3b724740120 GIT binary patch literal 17895 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

F_rjm0c)!6Y2}OHe&-X%jjTyxio|-x&^Jq45Me5 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 + + + + + + + diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java new file mode 100644 index 0000000..c044dc8 --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java @@ -0,0 +1,277 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 30/04/17. + */ + +public class Rx2GetJSONApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2GetJSONApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testJSONObjectGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getJSONObjectObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONObjectGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getJSONObjectObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testJSONArrayGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getJSONArrayObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONArrayGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getJSONArrayObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java new file mode 100644 index 0000000..e5461d4 --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java @@ -0,0 +1,268 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; +import com.rx2androidnetworking.model.User; + +import org.junit.Rule; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 26/04/17. + */ + +public class Rx2GetObjectApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2GetObjectApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testObjectGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getObjectObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getObjectObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(User user) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testObjectListGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getObjectListObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectListGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getObjectListObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(List userList) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java new file mode 100644 index 0000000..4f8ba77 --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java @@ -0,0 +1,160 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; + +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 22/04/17. + */ + +public class Rx2GetStringApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2GetStringApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testStringGetRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getStringObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(String response) { + responseRef.set(response); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("data", responseRef.get()); + } + + public void testStringGetRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.get(server.url("/").toString()) + .build() + .getStringObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(String response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java new file mode 100644 index 0000000..bdddbcc --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java @@ -0,0 +1,281 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 03/05/17. + */ + +public class Rx2MultipartJSONApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2MultipartJSONApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testJSONObjectMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getJSONObjectObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONObjectMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getJSONObjectObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testJSONArrayMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getJSONArrayObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONArrayMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getJSONArrayObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java new file mode 100644 index 0000000..ae74aa5 --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java @@ -0,0 +1,272 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; +import com.rx2androidnetworking.model.User; + +import org.junit.Rule; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 29/04/17. + */ + +public class Rx2MultipartObjectApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2MultipartObjectApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testObjectMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getObjectObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getObjectObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(User user) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testObjectListMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getObjectListObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectListMultipartRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getObjectListObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(List userList) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java new file mode 100644 index 0000000..dc9fb6e --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java @@ -0,0 +1,162 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; + +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 25/04/17. + */ + +public class Rx2MultipartStringApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2MultipartStringApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testStringMultipartRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getStringObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(String response) { + responseRef.set(response); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("data", responseRef.get()); + } + + public void testStringPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.upload(server.url("/").toString()) + .addMultipartParameter("key", "value") + .build() + .getStringObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(String response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + +} \ No newline at end of file diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java new file mode 100644 index 0000000..b3caebc --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java @@ -0,0 +1,285 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 02/05/17. + */ + +public class Rx2PostJSONApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2PostJSONApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testJSONObjectPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getJSONObjectObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONObject response) { + try { + firstNameRef.set(response.getString("firstName")); + lastNameRef.set(response.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONObjectPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getJSONObjectObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONObject response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testJSONArrayPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getJSONArrayObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONArray response) { + try { + JSONObject jsonObject = response.getJSONObject(0); + firstNameRef.set(jsonObject.getString("firstName")); + lastNameRef.set(jsonObject.getString("lastName")); + latch.countDown(); + } catch (JSONException e) { + assertTrue(false); + } + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testJSONArrayPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getJSONArrayObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(JSONArray response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java new file mode 100644 index 0000000..544f494 --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java @@ -0,0 +1,276 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; +import com.rx2androidnetworking.model.User; + +import org.junit.Rule; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 28/04/17. + */ + +public class Rx2PostObjectApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2PostObjectApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testObjectPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getObjectObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(User user) { + firstNameRef.set(user.firstName); + lastNameRef.set(user.lastName); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getObjectObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(User user) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + + public void testObjectListPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("[{\"firstName\":\"Amit\", \"lastName\":\"Shekhar\"}]")); + + final AtomicReference firstNameRef = new AtomicReference<>(); + final AtomicReference lastNameRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getObjectListObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(List userList) { + firstNameRef.set(userList.get(0).firstName); + lastNameRef.set(userList.get(0).lastName); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("Amit", firstNameRef.get()); + assertEquals("Shekhar", lastNameRef.get()); + } + + public void testObjectListPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getObjectListObservable(User.class) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(List userList) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } +} diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java new file mode 100644 index 0000000..3ba9f0d --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java @@ -0,0 +1,164 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.app.Application; +import android.test.ApplicationTestCase; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.error.ANError; + +import org.junit.Rule; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Created by amitshekhar on 24/04/17. + */ + +public class Rx2PostStringApiTest extends ApplicationTestCase { + + @Rule + public final MockWebServer server = new MockWebServer(); + + public Rx2PostStringApiTest() { + super(Application.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createApplication(); + } + + public void testStringPostRequest() throws InterruptedException { + + server.enqueue(new MockResponse().setBody("data")); + + final AtomicReference responseRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final AtomicReference isCompletedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(2); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getStringObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(String response) { + responseRef.set(response); + latch.countDown(); + } + + @Override + public void onError(Throwable e) { + assertTrue(false); + } + + @Override + public void onComplete() { + isCompletedRef.set(true); + latch.countDown(); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + assertTrue(isCompletedRef.get()); + + assertEquals("data", responseRef.get()); + } + + public void testStringPostRequest404() throws InterruptedException { + + server.enqueue(new MockResponse().setResponseCode(404).setBody("data")); + + final AtomicReference errorDetailRef = new AtomicReference<>(); + final AtomicReference errorBodyRef = new AtomicReference<>(); + final AtomicReference errorCodeRef = new AtomicReference<>(); + final AtomicReference isSubscribedRef = new AtomicReference<>(); + final CountDownLatch latch = new CountDownLatch(1); + + Rx2AndroidNetworking.post(server.url("/").toString()) + .addBodyParameter("fistName", "Amit") + .addBodyParameter("lastName", "Shekhar") + .build() + .getStringObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + isSubscribedRef.set(true); + } + + @Override + public void onNext(String response) { + assertTrue(false); + } + + @Override + public void onError(Throwable e) { + ANError anError = (ANError) e; + errorBodyRef.set(anError.getErrorBody()); + errorDetailRef.set(anError.getErrorDetail()); + errorCodeRef.set(anError.getErrorCode()); + latch.countDown(); + } + + @Override + public void onComplete() { + assertTrue(false); + } + }); + + assertTrue(latch.await(2, SECONDS)); + + assertTrue(isSubscribedRef.get()); + + assertEquals(ANConstants.RESPONSE_FROM_SERVER_ERROR, errorDetailRef.get()); + + assertEquals("data", errorBodyRef.get()); + + assertEquals(404, errorCodeRef.get().intValue()); + + } + +} \ No newline at end of file diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java new file mode 100644 index 0000000..4c91f7b --- /dev/null +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java @@ -0,0 +1,31 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking.model; + +/** + * Created by amitshekhar on 26/04/17. + */ + +public class User { + + public String firstName; + public String lastName; + +} diff --git a/rx2-android-networking/src/main/AndroidManifest.xml b/rx2-android-networking/src/main/AndroidManifest.xml new file mode 100644 index 0000000..40fbb9e --- /dev/null +++ b/rx2-android-networking/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + diff --git a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java new file mode 100644 index 0000000..0d8c4d8 --- /dev/null +++ b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java @@ -0,0 +1,223 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.graphics.Bitmap; + +import com.androidnetworking.common.ANRequest; +import com.androidnetworking.common.Method; +import com.androidnetworking.common.RequestType; +import com.androidnetworking.common.ResponseType; +import com.google.gson.internal.$Gson$Types; +import com.google.gson.reflect.TypeToken; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.List; + +import io.reactivex.Observable; + +/** + * Created by Prashant Gupta on 30-01-2017. + */ +@SuppressWarnings({"unchecked", "unused"}) +public class Rx2ANRequest extends ANRequest { + + public Rx2ANRequest(GetRequestBuilder builder) { + super(builder); + } + + public Rx2ANRequest(PostRequestBuilder builder) { + super(builder); + } + + public Rx2ANRequest(DownloadBuilder builder) { + super(builder); + } + + public Rx2ANRequest(MultiPartBuilder builder) { + super(builder); + } + + public Observable getJSONObjectObservable() { + this.setResponseAs(ResponseType.JSON_OBJECT); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public Observable getJSONArrayObservable() { + this.setResponseAs(ResponseType.JSON_ARRAY); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public Observable getBitmapObservable() { + this.setResponseAs(ResponseType.BITMAP); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public Observable getStringObservable() { + this.setResponseAs(ResponseType.STRING); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public Observable getDownloadObservable() { + return Rx2InternalNetworking.generateDownloadObservable(this); + } + + public Observable getParseObservable(TypeToken typeToken) { + this.setType(typeToken.getType()); + this.setResponseAs(ResponseType.PARSED); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public Observable getObjectObservable(Class objectClass) { + this.setType(objectClass); + this.setResponseAs(ResponseType.PARSED); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public Observable> getObjectListObservable(Class objectClass) { + this.setType($Gson$Types.newParameterizedTypeWithOwner(null, List.class, objectClass)); + this.setResponseAs(ResponseType.PARSED); + if (this.getRequestType() == RequestType.SIMPLE) { + return Rx2InternalNetworking.generateSimpleObservable(this); + } else if (this.getRequestType() == RequestType.MULTIPART) { + return Rx2InternalNetworking.generateMultipartObservable(this); + } else { + return null; + } + } + + public static class GetRequestBuilder extends ANRequest.GetRequestBuilder { + + public GetRequestBuilder(String url) { + super(url); + } + + private GetRequestBuilder(String url, int method) { + super(url, method); + } + + public Rx2ANRequest build() { + return new Rx2ANRequest(this); + } + } + + public static class HeadRequestBuilder extends GetRequestBuilder { + + public HeadRequestBuilder(String url) { + super(url, Method.HEAD); + } + } + + public static class PostRequestBuilder extends ANRequest.PostRequestBuilder { + + public PostRequestBuilder(String url) { + super(url); + } + + private PostRequestBuilder(String url, int method) { + super(url, method); + } + + public Rx2ANRequest build() { + return new Rx2ANRequest(this); + } + } + + public static class PutRequestBuilder extends PostRequestBuilder { + + public PutRequestBuilder(String url) { + super(url, Method.PUT); + } + } + + public static class DeleteRequestBuilder extends PostRequestBuilder { + + public DeleteRequestBuilder(String url) { + super(url, Method.DELETE); + } + } + + public static class PatchRequestBuilder extends PostRequestBuilder { + + public PatchRequestBuilder(String url) { + super(url, Method.PATCH); + } + } + + public static class DownloadBuilder extends ANRequest.DownloadBuilder { + + public DownloadBuilder(String url, String dirPath, String fileName) { + super(url, dirPath, fileName); + } + + public Rx2ANRequest build() { + return new Rx2ANRequest(this); + } + } + + public static class MultiPartBuilder extends ANRequest.MultiPartBuilder { + + public MultiPartBuilder(String url) { + super(url); + } + + public Rx2ANRequest build() { + return new Rx2ANRequest(this); + } + } +} diff --git a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java new file mode 100644 index 0000000..15d62c8 --- /dev/null +++ b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java @@ -0,0 +1,120 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +/** + * Created by amitshekhar on 30/01/17. + */ + +/** + * Rx2AndroidNetworking entry point. + * You must initialize this class before use. The simplest way is to just do + * {#code AndroidNetworking.initialize(context)}. + */ +public class Rx2AndroidNetworking { + + /** + * private constructor to prevent instantiation of this class + */ + private Rx2AndroidNetworking() { + } + + /** + * Method to make GET request + * + * @param url The url on which request is to be made + * @return The GetRequestBuilder + */ + public static Rx2ANRequest.GetRequestBuilder get(String url) { + return new Rx2ANRequest.GetRequestBuilder(url); + } + + /** + * Method to make HEAD request + * + * @param url The url on which request is to be made + * @return The HeadRequestBuilder + */ + public static Rx2ANRequest.HeadRequestBuilder head(String url) { + return new Rx2ANRequest.HeadRequestBuilder(url); + } + + /** + * Method to make POST request + * + * @param url The url on which request is to be made + * @return The PostRequestBuilder + */ + public static Rx2ANRequest.PostRequestBuilder post(String url) { + return new Rx2ANRequest.PostRequestBuilder(url); + } + + /** + * Method to make PUT request + * + * @param url The url on which request is to be made + * @return The PutRequestBuilder + */ + public static Rx2ANRequest.PutRequestBuilder put(String url) { + return new Rx2ANRequest.PutRequestBuilder(url); + } + + /** + * Method to make DELETE request + * + * @param url The url on which request is to be made + * @return The DeleteRequestBuilder + */ + public static Rx2ANRequest.DeleteRequestBuilder delete(String url) { + return new Rx2ANRequest.DeleteRequestBuilder(url); + } + + /** + * Method to make PATCH request + * + * @param url The url on which request is to be made + * @return The PatchRequestBuilder + */ + public static Rx2ANRequest.PatchRequestBuilder patch(String url) { + return new Rx2ANRequest.PatchRequestBuilder(url); + } + + /** + * Method to make download request + * + * @param url The url on which request is to be made + * @param dirPath The directory path on which file is to be saved + * @param fileName The file name with which file is to be saved + * @return The DownloadBuilder + */ + public static Rx2ANRequest.DownloadBuilder download(String url, String dirPath, String fileName) { + return new Rx2ANRequest.DownloadBuilder(url, dirPath, fileName); + } + + /** + * Method to make upload request + * + * @param url The url on which request is to be made + * @return The MultiPartBuilder + */ + public static Rx2ANRequest.MultiPartBuilder upload(String url) { + return new Rx2ANRequest.MultiPartBuilder(url); + } +} diff --git a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java new file mode 100644 index 0000000..4d8a373 --- /dev/null +++ b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java @@ -0,0 +1,441 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import android.net.TrafficStats; + +import com.androidnetworking.common.ANConstants; +import com.androidnetworking.common.ANResponse; +import com.androidnetworking.common.ConnectionClassManager; +import com.androidnetworking.error.ANError; +import com.androidnetworking.internal.InternalNetworking; +import com.androidnetworking.internal.RequestProgressBody; +import com.androidnetworking.internal.ResponseProgressBody; +import com.androidnetworking.utils.SourceCloseUtil; +import com.androidnetworking.utils.Utils; + +import java.io.File; +import java.io.IOException; + +import io.reactivex.Observable; +import io.reactivex.Observer; +import io.reactivex.disposables.Disposable; +import io.reactivex.exceptions.CompositeException; +import io.reactivex.exceptions.Exceptions; +import io.reactivex.plugins.RxJavaPlugins; +import okhttp3.Call; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import static com.androidnetworking.common.Method.DELETE; +import static com.androidnetworking.common.Method.GET; +import static com.androidnetworking.common.Method.HEAD; +import static com.androidnetworking.common.Method.PATCH; +import static com.androidnetworking.common.Method.POST; +import static com.androidnetworking.common.Method.PUT; + +/** + * Created by Prashant Gupta on 30-01-2017. + */ +@SuppressWarnings("unchecked") +public class Rx2InternalNetworking { + + public static Observable generateSimpleObservable(Rx2ANRequest request) { + Request okHttpRequest; + Request.Builder builder = new Request.Builder().url(request.getUrl()); + InternalNetworking.addHeadersToRequestBuilder(builder, request); + RequestBody requestBody; + switch (request.getMethod()) { + case GET: { + builder = builder.get(); + break; + } + case POST: { + requestBody = request.getRequestBody(); + builder = builder.post(requestBody); + break; + } + case PUT: { + requestBody = request.getRequestBody(); + builder = builder.put(requestBody); + break; + } + case DELETE: { + requestBody = request.getRequestBody(); + builder = builder.delete(requestBody); + break; + } + case HEAD: { + builder = builder.head(); + break; + } + case PATCH: { + requestBody = request.getRequestBody(); + builder = builder.patch(requestBody); + break; + } + } + if (request.getCacheControl() != null) { + builder.cacheControl(request.getCacheControl()); + } + okHttpRequest = builder.build(); + if (request.getOkHttpClient() != null) { + request.setCall(request + .getOkHttpClient() + .newBuilder() + .cache(InternalNetworking.sHttpClient.cache()) + .build() + .newCall(okHttpRequest)); + } else { + request.setCall(InternalNetworking.sHttpClient.newCall(okHttpRequest)); + } + return new SimpleANObservable<>(request); + } + + public static Observable generateDownloadObservable(final Rx2ANRequest request) { + Request okHttpRequest; + Request.Builder builder = new Request.Builder().url(request.getUrl()); + InternalNetworking.addHeadersToRequestBuilder(builder, request); + builder = builder.get(); + if (request.getCacheControl() != null) { + builder.cacheControl(request.getCacheControl()); + } + okHttpRequest = builder.build(); + + OkHttpClient okHttpClient; + + if (request.getOkHttpClient() != null) { + okHttpClient = request + .getOkHttpClient() + .newBuilder() + .cache(InternalNetworking.sHttpClient.cache()) + .addNetworkInterceptor(new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ResponseProgressBody(originalResponse.body(), + request.getDownloadProgressListener())) + .build(); + } + }).build(); + } else { + okHttpClient = InternalNetworking.sHttpClient.newBuilder() + .addNetworkInterceptor(new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ResponseProgressBody(originalResponse.body(), + request.getDownloadProgressListener())) + .build(); + } + }).build(); + } + request.setCall(okHttpClient.newCall(okHttpRequest)); + return new DownloadANObservable<>(request); + } + + public static Observable generateMultipartObservable(final Rx2ANRequest request) { + return new MultipartANObservable<>(request); + } + + static final class SimpleANObservable extends Observable { + + private Rx2ANRequest request; + private final Call originalCall; + + SimpleANObservable(Rx2ANRequest request) { + this.request = request; + this.originalCall = request.getCall(); + } + + @Override + protected void subscribeActual(Observer observer) { + Call call = originalCall.clone(); + observer.onSubscribe(new ANDisposable(call)); + boolean doNotSwallowError = false; + Response okHttpResponse = null; + try { + final long startTime = System.currentTimeMillis(); + final long startBytes = TrafficStats.getTotalRxBytes(); + okHttpResponse = call.execute(); + final long timeTaken = System.currentTimeMillis() - startTime; + if (okHttpResponse.cacheResponse() == null) { + final long finalBytes = TrafficStats.getTotalRxBytes(); + final long diffBytes; + if (startBytes == TrafficStats.UNSUPPORTED || finalBytes == TrafficStats.UNSUPPORTED) { + diffBytes = okHttpResponse.body().contentLength(); + } else { + diffBytes = finalBytes - startBytes; + } + ConnectionClassManager.getInstance().updateBandwidth(diffBytes, timeTaken); + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + (request.getRequestBody() != null && + request.getRequestBody().contentLength() != 0) ? + request.getRequestBody().contentLength() : -1, + okHttpResponse.body().contentLength(), false); + } else if (request.getAnalyticsListener() != null) { + if (okHttpResponse.networkResponse() == null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, 0, 0, true); + } else { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + (request.getRequestBody() != null && request.getRequestBody().contentLength() != 0) ? + request.getRequestBody().contentLength() : -1, 0, true); + } + } + if (okHttpResponse.code() >= 400) { + if (!call.isCanceled()) { + observer.onError(Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + } + } else { + ANResponse response = request.parseResponse(okHttpResponse); + if (!response.isSuccess()) { + if (!call.isCanceled()) { + observer.onError(response.getError()); + } + } else { + if (!call.isCanceled()) { + observer.onNext(response.getResult()); + } + if (!call.isCanceled()) { + doNotSwallowError = true; + observer.onComplete(); + } + } + } + } catch (IOException ioe) { + if (!call.isCanceled()) { + observer.onError(Utils.getErrorForConnection(new ANError(ioe))); + } + } catch (Exception e) { + Exceptions.throwIfFatal(e); + if (doNotSwallowError) { + RxJavaPlugins.onError(e); + } else if (!call.isCanceled()) { + try { + observer.onError(Utils.getErrorForNetworkOnMainThreadOrConnection(e)); + } catch (Exception e1) { + Exceptions.throwIfFatal(e1); + RxJavaPlugins.onError(new CompositeException(e, e1)); + } + } + } finally { + SourceCloseUtil.close(okHttpResponse, request); + } + } + } + + static final class DownloadANObservable extends Observable { + + private final Rx2ANRequest request; + private final Call originalCall; + + DownloadANObservable(Rx2ANRequest request) { + this.request = request; + this.originalCall = request.getCall(); + } + + @Override + protected void subscribeActual(Observer observer) { + Call call = originalCall.clone(); + observer.onSubscribe(new ANDisposable(call)); + boolean doNotSwallowError = false; + Response okHttpResponse; + try { + final long startTime = System.currentTimeMillis(); + final long startBytes = TrafficStats.getTotalRxBytes(); + okHttpResponse = request.getCall().execute(); + Utils.saveFile(okHttpResponse, request.getDirPath(), request.getFileName()); + final long timeTaken = System.currentTimeMillis() - startTime; + if (okHttpResponse.cacheResponse() == null) { + final long finalBytes = TrafficStats.getTotalRxBytes(); + final long diffBytes; + if (startBytes == TrafficStats.UNSUPPORTED || + finalBytes == TrafficStats.UNSUPPORTED) { + diffBytes = okHttpResponse.body().contentLength(); + } else { + diffBytes = finalBytes - startBytes; + } + ConnectionClassManager.getInstance().updateBandwidth(diffBytes, timeTaken); + Utils.sendAnalytics(request.getAnalyticsListener(), + timeTaken, -1, okHttpResponse.body().contentLength(), false); + } else if (request.getAnalyticsListener() != null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, -1, 0, true); + } + if (okHttpResponse.code() >= 400) { + if (!call.isCanceled()) { + observer.onError(Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + } + } else { + if (!call.isCanceled()) { + ANResponse response = (ANResponse) ANResponse.success(ANConstants.SUCCESS); + observer.onNext(response.getResult()); + } + if (!call.isCanceled()) { + doNotSwallowError = true; + observer.onComplete(); + } + } + } catch (IOException ioe) { + try { + File destinationFile = new File(request.getDirPath() + File.separator + request.getFileName()); + if (destinationFile.exists()) { + destinationFile.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + if (!call.isCanceled()) { + observer.onError(Utils.getErrorForConnection(new ANError(ioe))); + } + } catch (Exception e) { + Exceptions.throwIfFatal(e); + if (doNotSwallowError) { + RxJavaPlugins.onError(e); + } else if (!call.isCanceled()) { + try { + observer.onError(Utils.getErrorForNetworkOnMainThreadOrConnection(e)); + } catch (Exception e1) { + Exceptions.throwIfFatal(e1); + RxJavaPlugins.onError(new CompositeException(e, e1)); + } + } + } + } + } + + static final class MultipartANObservable extends Observable { + + private final Rx2ANRequest request; + + MultipartANObservable(Rx2ANRequest request) { + this.request = request; + } + + @Override + protected void subscribeActual(Observer observer) { + boolean doNotSwallowError = false; + Response okHttpResponse = null; + Request okHttpRequest; + try { + Request.Builder builder = new Request.Builder().url(request.getUrl()); + InternalNetworking.addHeadersToRequestBuilder(builder, request); + final RequestBody requestBody = request.getMultiPartRequestBody(); + final long requestBodyLength = requestBody.contentLength(); + builder = builder.post(new RequestProgressBody(requestBody, request.getUploadProgressListener())); + if (request.getCacheControl() != null) { + builder.cacheControl(request.getCacheControl()); + } + okHttpRequest = builder.build(); + if (request.getOkHttpClient() != null) { + request.setCall(request + .getOkHttpClient() + .newBuilder() + .cache(InternalNetworking.sHttpClient.cache()) + .build() + .newCall(okHttpRequest)); + } else { + request.setCall(InternalNetworking.sHttpClient.newCall(okHttpRequest)); + } + observer.onSubscribe(new ANDisposable(request.getCall())); + final long startTime = System.currentTimeMillis(); + okHttpResponse = request.getCall().execute(); + final long timeTaken = System.currentTimeMillis() - startTime; + if (request.getAnalyticsListener() != null) { + if (okHttpResponse.cacheResponse() == null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + requestBodyLength, okHttpResponse.body().contentLength(), false); + } else { + if (okHttpResponse.networkResponse() == null) { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, 0, 0, true); + } else { + Utils.sendAnalytics(request.getAnalyticsListener(), timeTaken, + requestBodyLength != 0 ? requestBodyLength : -1, 0, true); + } + } + } + if (okHttpResponse.code() >= 400) { + if (!request.getCall().isCanceled()) { + observer.onError(Utils.getErrorForServerResponse(new ANError(okHttpResponse), + request, okHttpResponse.code())); + } + } else { + ANResponse response = request.parseResponse(okHttpResponse); + if (!response.isSuccess()) { + if (!request.getCall().isCanceled()) { + observer.onError(response.getError()); + } + } else { + if (!request.getCall().isCanceled()) { + observer.onNext(response.getResult()); + } + if (!request.getCall().isCanceled()) { + doNotSwallowError = true; + observer.onComplete(); + } + } + } + } catch (IOException ioe) { + if (!request.getCall().isCanceled()) { + observer.onError(Utils.getErrorForConnection(new ANError(ioe))); + } + } catch (Exception e) { + Exceptions.throwIfFatal(e); + if (doNotSwallowError) { + RxJavaPlugins.onError(e); + } else if (!request.getCall().isCanceled()) { + try { + observer.onError(Utils.getErrorForNetworkOnMainThreadOrConnection(e)); + } catch (Exception e1) { + Exceptions.throwIfFatal(e1); + RxJavaPlugins.onError(new CompositeException(e, e1)); + } + } + } finally { + SourceCloseUtil.close(okHttpResponse, request); + } + } + } + + private static final class ANDisposable implements Disposable { + + private final Call call; + + private ANDisposable(Call call) { + this.call = call; + } + + @Override + public void dispose() { + this.call.cancel(); + } + + @Override + public boolean isDisposed() { + return this.call.isCanceled(); + } + } +} diff --git a/rx2-android-networking/src/main/res/values/strings.xml b/rx2-android-networking/src/main/res/values/strings.xml new file mode 100644 index 0000000..c5e2584 --- /dev/null +++ b/rx2-android-networking/src/main/res/values/strings.xml @@ -0,0 +1,22 @@ + + + + Rx2AndroidNetworking + diff --git a/rx2-android-networking/src/test/java/com/rx2androidnetworking/ExampleUnitTest.java b/rx2-android-networking/src/test/java/com/rx2androidnetworking/ExampleUnitTest.java new file mode 100644 index 0000000..a650ac4 --- /dev/null +++ b/rx2-android-networking/src/test/java/com/rx2androidnetworking/ExampleUnitTest.java @@ -0,0 +1,36 @@ +/* + * + * * Copyright (C) 2016 Amit Shekhar + * * Copyright (C) 2011 Android Open Source Project + * * + * * 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.rx2androidnetworking; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index e7b4def..6e43266 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app' +include ':app', ':android-networking', ':rx2-android-networking' From 1707a88aa680c5c7947dac4663ccfcb1f6b2c8cb Mon Sep 17 00:00:00 2001 From: kbuckler Date: Fri, 14 Jul 2017 22:33:44 -0600 Subject: [PATCH 3/7] fix build --- README.md | 2 + android-networking/build.gradle | 2 +- android-networking/upload.gradle | 101 ---------------------- app/build.gradle | 6 +- rx2-android-networking/build.gradle | 2 +- rx2-android-networking/rx2-upload.gradle | 103 ----------------------- 6 files changed, 8 insertions(+), 208 deletions(-) delete mode 100755 android-networking/upload.gradle delete mode 100755 rx2-android-networking/rx2-upload.gradle diff --git a/README.md b/README.md index 99acf09..33125df 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ From RxJava2 Android Studio "File/New Module/Import Gradle Project" Only select modules "android-networking" and "rx2-android-networking" +Add both modules to app module dependency + Note: original fork had network bug in gradle.properties ### Built to learn RxJava2 diff --git a/android-networking/build.gradle b/android-networking/build.gradle index 1750305..3b327c1 100644 --- a/android-networking/build.gradle +++ b/android-networking/build.gradle @@ -43,4 +43,4 @@ dependencies { compile 'com.squareup.okhttp3:okhttp:3.6.0' compile 'com.google.code.gson:gson:2.8.0' } -//apply from: 'upload.gradle' +//apply from: 'upload.gradle' \ No newline at end of file diff --git a/android-networking/upload.gradle b/android-networking/upload.gradle deleted file mode 100755 index 7580a50..0000000 --- a/android-networking/upload.gradle +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016 Amit Shekhar - * Copyright (C) 2011 Android Open Source Project - * - * 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. - */ - -apply plugin: 'com.github.dcendents.android-maven' -apply plugin: "com.jfrog.bintray" - -def siteUrl = 'https://github.com/amitshekhariitbhu/Fast-Android-Networking' -def gitUrl = 'https://github.com/amitshekhariitbhu/Fast-Android-Networking.git' - -group = "com.amitshekhar.android" -version = '1.0.0' - -install { - repositories.mavenInstaller { - pom.project { - packaging 'aar' - - name 'Fast Android Networking' - description 'Fast Android Networking is a powerful library for doing any type of networking in Android applications' - - url siteUrl - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - - developers { - developer { - id 'amitshekhariitbhu' - name 'Amit Shekhar' - email 'amit.shekhar.iitbhu@gmail.com' - } - } - - scm { - connection gitUrl - developerConnection gitUrl - url siteUrl - } - } - } -} - -task sourcesJar(type: Jar) { - from android.sourceSets.main.java.srcDirs - classifier = 'sources' -} - -task javadoc(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - classpath += configurations.compile -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} -artifacts { - archives javadocJar - archives sourcesJar -} - -if (project.rootProject.file("local.properties").exists()) { - Properties properties = new Properties() - properties.load(project.rootProject.file('local.properties').newDataInputStream()) - - bintray { - user = properties.getProperty("bintray.user") - key = properties.getProperty("bintray.apikey") - - configurations = ['archives'] - dryRun = false - - pkg { - repo = "maven" - name = "android-networking" - websiteUrl = siteUrl - vcsUrl = gitUrl - licenses = ["Apache-2.0"] - publish = true - } - } -} diff --git a/app/build.gradle b/app/build.gradle index 7f9dfae..af233ac 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,10 +20,12 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) + compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:25.1.0' compile 'com.android.support:recyclerview-v7:25.1.0' compile 'io.reactivex.rxjava2:rxjava:2.1.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' -} + compile project(':android-networking') + compile project(':rx2-android-networking') +} \ No newline at end of file diff --git a/rx2-android-networking/build.gradle b/rx2-android-networking/build.gradle index 5ec418d..30cb326 100644 --- a/rx2-android-networking/build.gradle +++ b/rx2-android-networking/build.gradle @@ -45,4 +45,4 @@ dependencies { compile 'io.reactivex.rxjava2:rxjava:2.0.5' compile project(':android-networking') } -//apply from: 'rx2-upload.gradle' +//apply from: 'rx2-upload.gradle' \ No newline at end of file diff --git a/rx2-android-networking/rx2-upload.gradle b/rx2-android-networking/rx2-upload.gradle deleted file mode 100755 index 4117e7b..0000000 --- a/rx2-android-networking/rx2-upload.gradle +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * * Copyright (C) 2016 Amit Shekhar - * * Copyright (C) 2011 Android Open Source Project - * * - * * 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. - * - */ - -apply plugin: 'com.github.dcendents.android-maven' -apply plugin: "com.jfrog.bintray" - -def siteUrl = 'https://github.com/amitshekhariitbhu/Fast-Android-Networking' -def gitUrl = 'https://github.com/amitshekhariitbhu/Fast-Android-Networking.git' - -group = "com.amitshekhar.android" -version = '1.0.0' - -install { - repositories.mavenInstaller { - pom.project { - packaging 'aar' - - name 'Fast Android Networking' - description 'Fast Android Networking is a powerful library for doing any type of networking in Android applications' - - url siteUrl - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - - developers { - developer { - id 'amitshekhariitbhu' - name 'Amit Shekhar' - email 'amit.shekhar.iitbhu@gmail.com' - } - } - - scm { - connection gitUrl - developerConnection gitUrl - url siteUrl - } - } - } -} - -task sourcesJar(type: Jar) { - from android.sourceSets.main.java.srcDirs - classifier = 'sources' -} - -task javadoc(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - classpath += configurations.compile -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} -artifacts { - archives javadocJar - archives sourcesJar -} - -if (project.rootProject.file("local.properties").exists()) { - Properties properties = new Properties() - properties.load(project.rootProject.file('local.properties').newDataInputStream()) - - bintray { - user = properties.getProperty("bintray.user") - key = properties.getProperty("bintray.apikey") - - configurations = ['archives'] - dryRun = false - - pkg { - repo = "maven" - name = "rx2-android-networking" - websiteUrl = siteUrl - vcsUrl = gitUrl - licenses = ["Apache-2.0"] - publish = true - } - } -} From c0929e1286ac52eb42a117d7906a790c134b679d Mon Sep 17 00:00:00 2001 From: kbuckler Date: Sat, 15 Jul 2017 02:19:25 -0600 Subject: [PATCH 4/7] change cricket to baseball and change heroku app --- README.md | 17 +++---- .../ui/networking/NetworkingActivity.java | 30 +++++------ .../ui/operators/SimpleExampleActivity.java | 2 +- .../ui/operators/ZipExampleActivity.java | 12 ++--- .../rxjava2/android/samples/utils/Utils.java | 50 +++++++++---------- 5 files changed, 54 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 33125df..5c97def 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,14 @@ # RxJava 2 for Android ### How to -Clone repo +* Clone repo +* Clone https://github.com/businesstek/Fast-Android-Networking +* From RxJava2 Android Studio "File/New Module/Import Gradle Project" +* Only select modules "android-networking" and "rx2-android-networking" +* Add both modules to app module dependency +* Note: original fork had network bug in gradle.properties +* Replace 6 calls in NetworkingActivity with your own node herokuapp to handle the REST calls -Clone https://github.com/businesstek/Fast-Android-Networking - -From RxJava2 Android Studio "File/New Module/Import Gradle Project" - -Only select modules "android-networking" and "rx2-android-networking" - -Add both modules to app module dependency - -Note: original fork had network bug in gradle.properties ### Built to learn RxJava2 diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java index f651870..896210e 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java @@ -44,7 +44,7 @@ protected void onCreate(Bundle savedInstanceState) { * Map Operator Example */ public void map(View view) { - Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAnUser/{userId}") + Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAnUser/{userId}") .addPathParameter("userId", "1") .build() .getObjectObservable(ApiUser.class) @@ -88,10 +88,10 @@ public void onComplete() { */ /** - * This observable return the list of User who loves cricket + * This observable return the list of User who loves baseball */ - private Observable> getCricketFansObservable() { - return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllCricketFans") + private Observable> getBaseballFansObservable() { + return Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAllBaseballFans") .build() .getObjectListObservable(User.class); } @@ -100,7 +100,7 @@ private Observable> getCricketFansObservable() { * This observable return the list of User who loves Football */ private Observable> getFootballFansObservable() { - return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllFootballFans") + return Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAllFootballFans") .build() .getObjectListObservable(User.class); } @@ -112,12 +112,12 @@ private Observable> getFootballFansObservable() { */ private void findUsersWhoLovesBoth() { // here we are using zip operator to combine both request - Observable.zip(getCricketFansObservable(), getFootballFansObservable(), + Observable.zip(getBaseballFansObservable(), getFootballFansObservable(), new BiFunction, List, List>() { @Override - public List apply(List cricketFans, List footballFans) throws Exception { + public List apply(List baseballFans, List footballFans) throws Exception { List userWhoLovesBoth = - filterUserWhoLovesBoth(cricketFans, footballFans); + filterUserWhoLovesBoth(baseballFans, footballFans); return userWhoLovesBoth; } }) @@ -150,12 +150,12 @@ public void onComplete() { }); } - private List filterUserWhoLovesBoth(List cricketFans, List footballFans) { + private List filterUserWhoLovesBoth(List baseballFans, List footballFans) { List userWhoLovesBoth = new ArrayList<>(); - for (User cricketFan : cricketFans) { + for (User baseballFan : baseballFans) { for (User footballFan : footballFans) { - if (cricketFan.id == footballFan.id) { - userWhoLovesBoth.add(cricketFan); + if (baseballFan.id == footballFan.id) { + userWhoLovesBoth.add(baseballFan); } } } @@ -173,7 +173,7 @@ public void zip(View view) { */ private Observable> getAllMyFriendsObservable() { - return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllFriends/{userId}") + return Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAllFriends/{userId}") .addPathParameter("userId", "1") .build() .getObjectListObservable(User.class); @@ -313,7 +313,7 @@ public void onComplete() { */ private Observable> getUserListObservable() { - return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllUsers/{pageNumber}") + return Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAllUsers/{pageNumber}") .addPathParameter("pageNumber", "0") .addQueryParameter("limit", "10") .build() @@ -321,7 +321,7 @@ private Observable> getUserListObservable() { } private Observable getUserDetailObservable(long id) { - return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAnUserDetail/{userId}") + return Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAnUserDetail/{userId}") .addPathParameter("userId", String.valueOf(id)) .build() .getObjectObservable(UserDetail.class); diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java index 423047d..3d4e9f1 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java @@ -53,7 +53,7 @@ private void doSomeWork() { } private Observable getObservable() { - return Observable.just("Cricket", "Football"); + return Observable.just("Baseball", "Football"); } private Observer getObserver() { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java index af446f3..a6ed6f2 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java @@ -49,16 +49,16 @@ public void onClick(View view) { /* * Here we are getting two user list - * One, the list of cricket fans + * One, the list of baseball fans * Another one, the list of football fans * Then we are finding the list of users who loves both */ private void doSomeWork() { - Observable.zip(getCricketFansObservable(), getFootballFansObservable(), + Observable.zip(getBaseballFansObservable(), getFootballFansObservable(), new BiFunction, List, List>() { @Override - public List apply(List cricketFans, List footballFans) throws Exception { - return Utils.filterUserWhoLovesBoth(cricketFans, footballFans); + public List apply(List baseballFans, List footballFans) throws Exception { + return Utils.filterUserWhoLovesBoth(baseballFans, footballFans); } }) // Run on a background thread @@ -68,12 +68,12 @@ public List apply(List cricketFans, List footballFans) throws .subscribe(getObserver()); } - private Observable> getCricketFansObservable() { + private Observable> getBaseballFansObservable() { return Observable.create(new ObservableOnSubscribe>() { @Override public void subscribe(ObservableEmitter> e) throws Exception { if (!e.isDisposed()) { - e.onNext(Utils.getUserListWhoLovesCricket()); + e.onNext(Utils.getUserListWhoLovesBaseball()); e.onComplete(); } } diff --git a/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java b/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java index 04695b2..e45171d 100644 --- a/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java +++ b/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java @@ -23,18 +23,18 @@ public static List getUserList() { List userList = new ArrayList<>(); User userOne = new User(); - userOne.firstname = "Amit"; - userOne.lastname = "Shekhar"; + userOne.firstname = "Able"; + userOne.lastname = "Black"; userList.add(userOne); User userTwo = new User(); - userTwo.firstname = "Manish"; - userTwo.lastname = "Kumar"; + userTwo.firstname = "Bly"; + userTwo.lastname = "Cane"; userList.add(userTwo); User userThree = new User(); - userThree.firstname = "Sumit"; - userThree.lastname = "Kumar"; + userThree.firstname = "Candy"; + userThree.lastname = "Donut"; userList.add(userThree); return userList; @@ -45,18 +45,18 @@ public static List getApiUserList() { List apiUserList = new ArrayList<>(); ApiUser apiUserOne = new ApiUser(); - apiUserOne.firstname = "Amit"; - apiUserOne.lastname = "Shekhar"; + apiUserOne.firstname = "Able"; + apiUserOne.lastname = "Black"; apiUserList.add(apiUserOne); ApiUser apiUserTwo = new ApiUser(); - apiUserTwo.firstname = "Manish"; - apiUserTwo.lastname = "Kumar"; + apiUserTwo.firstname = "Bly"; + apiUserTwo.lastname = "Cane"; apiUserList.add(apiUserTwo); ApiUser apiUserThree = new ApiUser(); - apiUserThree.firstname = "Sumit"; - apiUserThree.lastname = "Kumar"; + apiUserThree.firstname = "Candy"; + apiUserThree.lastname = "Donut"; apiUserList.add(apiUserThree); return apiUserList; @@ -76,20 +76,20 @@ public static List convertApiUserListToUserList(List apiUserList) return userList; } - public static List getUserListWhoLovesCricket() { + public static List getUserListWhoLovesBaseball() { List userList = new ArrayList<>(); User userOne = new User(); userOne.id = 1; - userOne.firstname = "Amit"; - userOne.lastname = "Shekhar"; + userOne.firstname = "Able"; + userOne.lastname = "Black"; userList.add(userOne); User userTwo = new User(); userTwo.id = 2; - userTwo.firstname = "Manish"; - userTwo.lastname = "Kumar"; + userTwo.firstname = "Bly"; + userTwo.lastname = "Cane"; userList.add(userTwo); return userList; @@ -102,26 +102,26 @@ public static List getUserListWhoLovesFootball() { User userOne = new User(); userOne.id = 1; - userOne.firstname = "Amit"; - userOne.lastname = "Shekhar"; + userOne.firstname = "Able"; + userOne.lastname = "Black"; userList.add(userOne); User userTwo = new User(); userTwo.id = 3; - userTwo.firstname = "Sumit"; - userTwo.lastname = "Kumar"; + userTwo.firstname = "Bly"; + userTwo.lastname = "Cane"; userList.add(userTwo); return userList; } - public static List filterUserWhoLovesBoth(List cricketFans, List footballFans) { + public static List filterUserWhoLovesBoth(List baseballFans, List footballFans) { List userWhoLovesBoth = new ArrayList(); - for (User cricketFan : cricketFans) { + for (User baseballFan : baseballFans) { for (User footballFan : footballFans) { - if (cricketFan.id == footballFan.id) { - userWhoLovesBoth.add(cricketFan); + if (baseballFan.id == footballFan.id) { + userWhoLovesBoth.add(baseballFan); } } } From 7fd67fe2805744efac345ad677e5a8f2c2fd22e1 Mon Sep 17 00:00:00 2001 From: kbuckler Date: Sat, 15 Jul 2017 17:44:26 -0600 Subject: [PATCH 5/7] Fix rest calls and add toast feedback --- README.md | 4 +- .../ui/networking/NetworkingActivity.java | 7 +- app/src/main/res/values/strings.xml | 2 +- assets/index.js | 108 ++++++++++++++++++ 4 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 assets/index.js diff --git a/README.md b/README.md index 5c97def..e21fdc0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ * Only select modules "android-networking" and "rx2-android-networking" * Add both modules to app module dependency * Note: original fork had network bug in gradle.properties -* Replace 6 calls in NetworkingActivity with your own node herokuapp to handle the REST calls +* Note: ApiUser and UserDetail models are the same. Why? +* Note: added toast for feedback for networking +* Replace 6 calls in NetworkingActivity with your own node herokuapp to handle the REST calls. Sample index.js is included in assets folder ### Built to learn RxJava2 diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java index 896210e..17a425a 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java @@ -5,6 +5,7 @@ import android.util.Log; import android.util.Pair; import android.view.View; +import android.widget.Toast; import com.rx2androidnetworking.Rx2AndroidNetworking; import com.rxjava2.android.samples.R; @@ -34,6 +35,7 @@ public class NetworkingActivity extends AppCompatActivity { public static final String TAG = NetworkingActivity.class.getSimpleName(); + String str = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -45,7 +47,7 @@ protected void onCreate(Bundle savedInstanceState) { */ public void map(View view) { Rx2AndroidNetworking.get("https://secret-ridge-27839.herokuapp.com/getAnUser/{userId}") - .addPathParameter("userId", "1") + .addPathParameter("userId", "12") .build() .getObjectObservable(ApiUser.class) .subscribeOn(Schedulers.io()) @@ -67,6 +69,7 @@ public void onSubscribe(Disposable d) { @Override public void onNext(User user) { + str = user.toString(); Log.d(TAG, "user : " + user.toString()); } @@ -77,6 +80,8 @@ public void onError(Throwable e) { @Override public void onComplete() { + Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show(); + Log.d(TAG, "onComplete"); } }); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cdd27c4..9ec3cc0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,7 +5,7 @@ Networking Pagination Simple - Map + Observe ApiUser Map to User Zip Disposable Take diff --git a/assets/index.js b/assets/index.js new file mode 100644 index 0000000..6cf1e91 --- /dev/null +++ b/assets/index.js @@ -0,0 +1,108 @@ +// +// go to path of heroku +// git add * +// git commit -m "fix" +// git push heroku master +// https://secret-ridge-27839.herokuapp.com/getAnUser/12 + +var express = require('express'); +var app = express(); + +var user = [{ + id: 12, + firstname: 'able', + lastname: 'black', + isfollowing: ['baseball'] + }, + { + id: 13, + firstname: 'bly', + lastname: 'cane', + isfollowing: ['football'] + }, + { + id: 14, + firstname: 'candy', + lastname: 'donut', + isfollowing: ['baseball', 'football'] + }]; + +var userdetail =[ + { + id: 12, + firstname: 'able', + lastname: 'black' + }, + { + id: 13, + firstname: 'bly', + lastname: 'cane' + }, + { + id: 14, + firstname: 'candy', + lastname: 'donut' + } +]; + +app.set('port', (process.env.PORT || 5000)); + +//for android app +app.get('/getAnUser/:userId', function(request, response) { + var id = request.params.userId; + var item = userdetail.filter(function(el) { + return (el.id == id); + }); +var str = JSON.stringify(item[0]); +response.send(str); +}); + +app.get('/getAllBaseballFans', function(request, response) { + var item = user.filter(function(el) { + return (el.isfollowing.indexOf("baseball") >= 0); + }); + var jObject={}; + for(i in item) + { + jObject[i] = item[i]; + } + response.send(jObject); +}); + +app.get('/getAllFootballFans', function(request, response) { + var item = user.filter(function(el) { + return (el.isfollowing.indexOf("football") >= 0); + }); + var jObject={}; + for(i in item) + { + jObject[i] = item[i]; + } + response.send(jObject); + +}); + +app.get('/getAllFriends/:userId', function(request, response) { + var id = request.params.userId; + var item = user.filter(function(el) { + return (el.id === id); + }); + response.send(item); +}); + +app.get('/getAllUsers', function(request, response) { + response.send(user); +}); + +app.get('/getAnUserDetail/:userId', function(request, response) { +var id = request.params.userId; + var item = userdetail.filter(function(el) { + return (el.id == id); + }); + response.send(item); +}); + + +app.listen(app.get('port'), function() { + console.log('Node app is running on port', app.get('port')); +}); From bbbf6755a7585653a5d2b63b58957737e1bc3f1a Mon Sep 17 00:00:00 2001 From: kbuckler Date: Thu, 20 Jul 2017 19:43:17 -0600 Subject: [PATCH 6/7] fix --- app/src/main/AndroidManifest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9b4c4f7..2a8cb2d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,6 @@ - From cf70d8a77612dfdd945b0f8a3106efb1074366ed Mon Sep 17 00:00:00 2001 From: kbuckler Date: Mon, 7 Aug 2017 18:51:53 -0600 Subject: [PATCH 7/7] fix comment --- README.md | 38 +++++++++---------- android-networking/proguard-rules.pro | 2 +- .../com/androidnetworking/GetJSONApiTest.java | 2 +- .../androidnetworking/GetObjectApiTest.java | 2 +- .../MultipartJSONApiTest.java | 2 +- .../MultipartObjectApiTest.java | 2 +- .../MultipartStringApiTest.java | 2 +- .../androidnetworking/PostJSONApiTest.java | 2 +- .../androidnetworking/PostObjectApiTest.java | 2 +- .../androidnetworking/PostStringApiTest.java | 2 +- .../com/androidnetworking/model/User.java | 2 +- .../androidnetworking/AndroidNetworking.java | 2 +- .../cache/LruBitmapCache.java | 2 +- .../com/androidnetworking/cache/LruCache.java | 2 +- .../androidnetworking/common/ANConstants.java | 2 +- .../androidnetworking/common/ANRequest.java | 2 +- .../androidnetworking/common/ANResponse.java | 2 +- .../common/ConnectionClassManager.java | 2 +- .../common/ConnectionQuality.java | 2 +- .../com/androidnetworking/common/Method.java | 2 +- .../androidnetworking/common/Priority.java | 2 +- .../common/RequestBuilder.java | 2 +- .../androidnetworking/common/RequestType.java | 2 +- .../common/ResponseType.java | 2 +- .../androidnetworking/core/ANExecutor.java | 2 +- .../java/com/androidnetworking/core/Core.java | 2 +- .../core/DefaultExecutorSupplier.java | 2 +- .../core/ExecutorSupplier.java | 2 +- .../core/MainThreadExecutor.java | 2 +- .../core/PriorityThreadFactory.java | 2 +- .../com/androidnetworking/error/ANError.java | 2 +- .../gsonparserfactory/GsonParserFactory.java | 2 +- .../GsonRequestBodyParser.java | 2 +- .../GsonResponseBodyParser.java | 2 +- .../interceptors/GzipRequestInterceptor.java | 2 +- .../interceptors/HttpLoggingInterceptor.java | 2 +- .../interfaces/AnalyticsListener.java | 2 +- .../interfaces/BitmapRequestListener.java | 2 +- .../ConnectionQualityChangeListener.java | 2 +- .../interfaces/DownloadListener.java | 2 +- .../interfaces/DownloadProgressListener.java | 2 +- .../interfaces/JSONArrayRequestListener.java | 2 +- .../interfaces/JSONObjectRequestListener.java | 2 +- ...kHttpResponseAndBitmapRequestListener.java | 2 +- ...tpResponseAndJSONArrayRequestListener.java | 2 +- ...pResponseAndJSONObjectRequestListener.java | 2 +- ...kHttpResponseAndParsedRequestListener.java | 2 +- ...kHttpResponseAndStringRequestListener.java | 2 +- .../interfaces/OkHttpResponseListener.java | 2 +- .../interfaces/ParsedRequestListener.java | 2 +- .../androidnetworking/interfaces/Parser.java | 2 +- .../interfaces/StringRequestListener.java | 2 +- .../interfaces/UploadProgressListener.java | 2 +- .../internal/ANImageLoader.java | 2 +- .../internal/ANRequestQueue.java | 2 +- .../internal/DownloadProgressHandler.java | 2 +- .../internal/InternalNetworking.java | 2 +- .../internal/InternalRunnable.java | 2 +- .../internal/RequestProgressBody.java | 2 +- .../internal/ResponseProgressBody.java | 2 +- .../internal/SynchronousCall.java | 2 +- .../internal/UploadProgressHandler.java | 2 +- .../com/androidnetworking/model/Progress.java | 2 +- .../androidnetworking/utils/ParseUtil.java | 2 +- .../utils/SourceCloseUtil.java | 2 +- .../com/androidnetworking/utils/Utils.java | 2 +- .../androidnetworking/widget/ANImageView.java | 2 +- app/proguard-rules.pro | 2 +- .../android/samples/model/ApiUser.java | 2 +- .../rxjava2/android/samples/model/Car.java | 2 +- .../rxjava2/android/samples/model/Events.java | 2 +- .../rxjava2/android/samples/model/User.java | 2 +- .../android/samples/model/UserDetail.java | 2 +- .../ui/networking/NetworkingActivity.java | 2 +- .../AsyncSubjectExampleActivity.java | 2 +- .../BehaviorSubjectExampleActivity.java | 2 +- .../ui/operators/BufferExampleActivity.java | 2 +- .../CompletableObserverExampleActivity.java | 2 +- .../ui/operators/ConcatExampleActivity.java | 2 +- .../ui/operators/DebounceExampleActivity.java | 2 +- .../ui/operators/DeferExampleActivity.java | 2 +- .../ui/operators/DelayExampleActivity.java | 2 +- .../operators/DisposableExampleActivity.java | 2 +- .../ui/operators/FilterExampleActivity.java | 2 +- .../ui/operators/FlowableExampleActivity.java | 2 +- .../ui/operators/IntervalExampleActivity.java | 2 +- .../ui/operators/MapExampleActivity.java | 2 +- .../ui/operators/MergeExampleActivity.java | 2 +- .../PublishSubjectExampleActivity.java | 2 +- .../ui/operators/ReduceExampleActivity.java | 2 +- .../ui/operators/ReplayExampleActivity.java | 2 +- .../ReplaySubjectExampleActivity.java | 2 +- .../ui/operators/SimpleExampleActivity.java | 2 +- .../SingleObserverExampleActivity.java | 2 +- .../ui/operators/SkipExampleActivity.java | 2 +- .../ui/operators/TakeExampleActivity.java | 2 +- .../ThrottleLastExampleActivity.java | 2 +- .../ui/operators/TimerExampleActivity.java | 2 +- .../ui/operators/ZipExampleActivity.java | 2 +- .../ui/pagination/PaginationActivity.java | 2 +- .../ui/pagination/PaginationAdapter.java | 2 +- .../android/samples/ui/rxbus/RxBus.java | 2 +- .../samples/ui/rxbus/RxBusActivity.java | 2 +- .../android/samples/utils/AppConstant.java | 2 +- .../rxjava2/android/samples/utils/Utils.java | 2 +- rx2-android-networking/proguard-rules.pro | 2 +- .../Rx2GetJSONApiTest.java | 2 +- .../Rx2GetObjectApiTest.java | 2 +- .../Rx2GetStringApiTest.java | 2 +- .../Rx2MultipartJSONApiTest.java | 2 +- .../Rx2MultipartObjectApiTest.java | 2 +- .../Rx2MultipartStringApiTest.java | 2 +- .../Rx2PostJSONApiTest.java | 2 +- .../Rx2PostObjectApiTest.java | 2 +- .../Rx2PostStringApiTest.java | 2 +- .../com/rx2androidnetworking/model/User.java | 2 +- .../rx2androidnetworking/Rx2ANRequest.java | 2 +- .../Rx2AndroidNetworking.java | 2 +- .../Rx2InternalNetworking.java | 2 +- 119 files changed, 137 insertions(+), 137 deletions(-) diff --git a/README.md b/README.md index e21fdc0..2b847cf 100644 --- a/README.md +++ b/README.md @@ -82,23 +82,23 @@ RxJava1 -> RxJava2 # Highlights of the examples : -* [DisposableExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/DisposableExampleActivity.java) - Using `CompositeDisposable` -* [FlowableExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/FlowableExampleActivity.java) - Using `Flowable` and `reduce` operator -* [SingleObserverExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/SingleObserverExampleActivity.java) - Using `SingleObserver` -* [CompletableObserverActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/CompletableObserverExampleActivity.java) - Using `CompletableObserver` -* [MapExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/MapExampleActivity.java) - Using `map` Operator -* [ZipExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java) - Using `zip` Operator -* [BufferExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/BufferExampleActivity.java) - Using `buffer` Operator -* [TakeExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/TakeExampleActivity.java) - Using `take` Operator -* [ReduceExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReduceExampleActivity.java) - Using `reduce` Operator -* [FilterExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/FilterExampleActivity.java) - Using `filter` Operator -* [SkipExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/SkipExampleActivity.java) - Using `skip` Operator -* [ReplayExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplayExampleActivity.java) - Using `replay` Operator -* [ConcatExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ConcatExampleActivity.java) - Using `concat` Operator -* [MergeExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/MergeExampleActivity.java) - Using `merge` Operator -* [DeferExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/DeferExampleActivity.java) - Using `defer` Observable -* [IntervalExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/IntervalExampleActivity.java) - Using `Interval` -* [RxBusActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBusActivity.java) - RxBus, RxJava2Bus, EventBus, RxEventBus -* [PaginationActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java) - Pagination for loadMore in RecyclerView -* [ComposeOperatorExampleActivity](https://github.com/amitshekhariitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/compose/ComposeOperatorExampleActivity.java) - Compose operator for reusable +* [DisposableExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/DisposableExampleActivity.java) - Using `CompositeDisposable` +* [FlowableExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/FlowableExampleActivity.java) - Using `Flowable` and `reduce` operator +* [SingleObserverExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/SingleObserverExampleActivity.java) - Using `SingleObserver` +* [CompletableObserverActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/CompletableObserverExampleActivity.java) - Using `CompletableObserver` +* [MapExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/MapExampleActivity.java) - Using `map` Operator +* [ZipExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java) - Using `zip` Operator +* [BufferExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/BufferExampleActivity.java) - Using `buffer` Operator +* [TakeExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/TakeExampleActivity.java) - Using `take` Operator +* [ReduceExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReduceExampleActivity.java) - Using `reduce` Operator +* [FilterExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/FilterExampleActivity.java) - Using `filter` Operator +* [SkipExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/SkipExampleActivity.java) - Using `skip` Operator +* [ReplayExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplayExampleActivity.java) - Using `replay` Operator +* [ConcatExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/ConcatExampleActivity.java) - Using `concat` Operator +* [MergeExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/MergeExampleActivity.java) - Using `merge` Operator +* [DeferExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/DeferExampleActivity.java) - Using `defer` Observable +* [IntervalExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/operators/IntervalExampleActivity.java) - Using `Interval` +* [RxBusActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBusActivity.java) - RxBus, RxJava2Bus, EventBus, RxEventBus +* [PaginationActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java) - Pagination for loadMore in RecyclerView +* [ComposeOperatorExampleActivity](https://github.com/owneriitbhu/RxJava2-Android-Samples/blob/master/app/src/main/java/com/rxjava2/android/samples/ui/compose/ComposeOperatorExampleActivity.java) - Compose operator for reusable diff --git a/android-networking/proguard-rules.pro b/android-networking/proguard-rules.pro index 3f19523..c88a38b 100644 --- a/android-networking/proguard-rules.pro +++ b/android-networking/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified -# in /Users/amitshekhar/Library/Android/sdk/tools/proguard/proguard-android.txt +# in /Users/owner/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # diff --git a/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java index 57e8e33..cab349d 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/GetJSONApiTest.java @@ -47,7 +47,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 03/04/17. + * Created by owner on 03/04/17. */ public class GetJSONApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java index e06a4ac..8409ab2 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/GetObjectApiTest.java @@ -45,7 +45,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 10/04/17. + * Created by owner on 10/04/17. */ public class GetObjectApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java index 3fdc4cf..de2cc93 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/MultipartJSONApiTest.java @@ -47,7 +47,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 09/04/17. + * Created by owner on 09/04/17. */ public class MultipartJSONApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java index e223381..021c244 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/MultipartObjectApiTest.java @@ -45,7 +45,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 12/04/17. + * Created by owner on 12/04/17. */ public class MultipartObjectApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java index af01aa9..30402bf 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/MultipartStringApiTest.java @@ -46,7 +46,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 27/03/17. + * Created by owner on 27/03/17. */ public class MultipartStringApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java index 2f9a244..c546b6a 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/PostJSONApiTest.java @@ -47,7 +47,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 06/04/17. + * Created by owner on 06/04/17. */ public class PostJSONApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java index 2865436..49a07b2 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/PostObjectApiTest.java @@ -45,7 +45,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 11/04/17. + * Created by owner on 11/04/17. */ public class PostObjectApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java b/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java index 17b527a..c931be6 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/PostStringApiTest.java @@ -44,7 +44,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 25/03/17. + * Created by owner on 25/03/17. */ public class PostStringApiTest extends ApplicationTestCase { diff --git a/android-networking/src/androidTest/java/com/androidnetworking/model/User.java b/android-networking/src/androidTest/java/com/androidnetworking/model/User.java index 4337a8f..a078877 100644 --- a/android-networking/src/androidTest/java/com/androidnetworking/model/User.java +++ b/android-networking/src/androidTest/java/com/androidnetworking/model/User.java @@ -20,7 +20,7 @@ package com.androidnetworking.model; /** - * Created by amitshekhar on 10/04/17. + * Created by owner on 10/04/17. */ public class User { diff --git a/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java b/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java index 290bfc6..e532cc9 100644 --- a/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java +++ b/android-networking/src/main/java/com/androidnetworking/AndroidNetworking.java @@ -37,7 +37,7 @@ import okhttp3.OkHttpClient; /** - * Created by amitshekhar on 24/03/16. + * Created by owner on 24/03/16. */ /** diff --git a/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java b/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java index a47d74f..9786eee 100644 --- a/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java +++ b/android-networking/src/main/java/com/androidnetworking/cache/LruBitmapCache.java @@ -22,7 +22,7 @@ import com.androidnetworking.internal.ANImageLoader; /** - * Created by amitshekhar on 24/03/16. + * Created by owner on 24/03/16. */ public class LruBitmapCache extends LruCache implements ANImageLoader.ImageCache { diff --git a/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java b/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java index 509d295..2cf3d6b 100644 --- a/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java +++ b/android-networking/src/main/java/com/androidnetworking/cache/LruCache.java @@ -23,7 +23,7 @@ import java.util.Map; /** - * Created by amitshekhar on 28/05/16. + * Created by owner on 28/05/16. */ public class LruCache { private final LinkedHashMap map; diff --git a/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java b/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java index cafda96..f633b47 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java +++ b/android-networking/src/main/java/com/androidnetworking/common/ANConstants.java @@ -18,7 +18,7 @@ package com.androidnetworking.common; /** - * Created by amitshekhar on 29/03/16. + * Created by owner on 29/03/16. */ public final class ANConstants { public static final int MAX_CACHE_SIZE = 10 * 1024 * 1024; diff --git a/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java b/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java index 9a18351..2edd98c 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java +++ b/android-networking/src/main/java/com/androidnetworking/common/ANRequest.java @@ -70,7 +70,7 @@ import okio.Okio; /** - * Created by amitshekhar on 26/03/16. + * Created by owner on 26/03/16. */ @SuppressWarnings({"unchecked", "unused"}) public class ANRequest { diff --git a/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java b/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java index be2dfa9..2b4e8d2 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java +++ b/android-networking/src/main/java/com/androidnetworking/common/ANResponse.java @@ -22,7 +22,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class ANResponse { diff --git a/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java b/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java index 5d94716..b903d38 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java +++ b/android-networking/src/main/java/com/androidnetworking/common/ConnectionClassManager.java @@ -21,7 +21,7 @@ import com.androidnetworking.interfaces.ConnectionQualityChangeListener; /** - * Created by amitshekhar on 29/05/16. + * Created by owner on 29/05/16. */ public class ConnectionClassManager { diff --git a/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java b/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java index 805d8a9..4eb0787 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java +++ b/android-networking/src/main/java/com/androidnetworking/common/ConnectionQuality.java @@ -18,7 +18,7 @@ package com.androidnetworking.common; /** - * Created by amitshekhar on 29/05/16. + * Created by owner on 29/05/16. */ public enum ConnectionQuality { /** diff --git a/android-networking/src/main/java/com/androidnetworking/common/Method.java b/android-networking/src/main/java/com/androidnetworking/common/Method.java index 1e05a17..1735743 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/Method.java +++ b/android-networking/src/main/java/com/androidnetworking/common/Method.java @@ -18,7 +18,7 @@ package com.androidnetworking.common; /** - * Created by amitshekhar on 26/03/16. + * Created by owner on 26/03/16. */ public interface Method { int GET = 0; diff --git a/android-networking/src/main/java/com/androidnetworking/common/Priority.java b/android-networking/src/main/java/com/androidnetworking/common/Priority.java index 3b37a5a..d763e71 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/Priority.java +++ b/android-networking/src/main/java/com/androidnetworking/common/Priority.java @@ -18,7 +18,7 @@ package com.androidnetworking.common; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ diff --git a/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java b/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java index 9e1adf3..a72cda3 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java +++ b/android-networking/src/main/java/com/androidnetworking/common/RequestBuilder.java @@ -24,7 +24,7 @@ import okhttp3.OkHttpClient; /** - * Created by amitshekhar on 26/03/16. + * Created by owner on 26/03/16. */ public interface RequestBuilder { diff --git a/android-networking/src/main/java/com/androidnetworking/common/RequestType.java b/android-networking/src/main/java/com/androidnetworking/common/RequestType.java index 9a928d0..88d70b2 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/RequestType.java +++ b/android-networking/src/main/java/com/androidnetworking/common/RequestType.java @@ -18,7 +18,7 @@ package com.androidnetworking.common; /** - * Created by amitshekhar on 04/04/16. + * Created by owner on 04/04/16. */ public interface RequestType { int SIMPLE = 0; diff --git a/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java b/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java index 36491e6..5a70c31 100644 --- a/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java +++ b/android-networking/src/main/java/com/androidnetworking/common/ResponseType.java @@ -18,7 +18,7 @@ package com.androidnetworking.common; /** - * Created by amitshekhar on 26/03/16. + * Created by owner on 26/03/16. */ public enum ResponseType { STRING, diff --git a/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java b/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java index 47c3e5d..948d41a 100644 --- a/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java +++ b/android-networking/src/main/java/com/androidnetworking/core/ANExecutor.java @@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class ANExecutor extends ThreadPoolExecutor { diff --git a/android-networking/src/main/java/com/androidnetworking/core/Core.java b/android-networking/src/main/java/com/androidnetworking/core/Core.java index 673b24f..95563f4 100644 --- a/android-networking/src/main/java/com/androidnetworking/core/Core.java +++ b/android-networking/src/main/java/com/androidnetworking/core/Core.java @@ -18,7 +18,7 @@ package com.androidnetworking.core; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class Core { diff --git a/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java b/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java index 9cec863..aac0017 100644 --- a/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java +++ b/android-networking/src/main/java/com/androidnetworking/core/DefaultExecutorSupplier.java @@ -23,7 +23,7 @@ import java.util.concurrent.ThreadFactory; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class DefaultExecutorSupplier implements ExecutorSupplier { diff --git a/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java b/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java index cddd115..16e9699 100644 --- a/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java +++ b/android-networking/src/main/java/com/androidnetworking/core/ExecutorSupplier.java @@ -20,7 +20,7 @@ import java.util.concurrent.Executor; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public interface ExecutorSupplier { diff --git a/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java b/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java index aa227cb..67e2c6f 100644 --- a/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java +++ b/android-networking/src/main/java/com/androidnetworking/core/MainThreadExecutor.java @@ -23,7 +23,7 @@ import java.util.concurrent.Executor; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class MainThreadExecutor implements Executor { diff --git a/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java b/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java index 3eacf9c..63dbe32 100644 --- a/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java +++ b/android-networking/src/main/java/com/androidnetworking/core/PriorityThreadFactory.java @@ -18,7 +18,7 @@ package com.androidnetworking.core; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ diff --git a/android-networking/src/main/java/com/androidnetworking/error/ANError.java b/android-networking/src/main/java/com/androidnetworking/error/ANError.java index 399e827..cc8a32f 100644 --- a/android-networking/src/main/java/com/androidnetworking/error/ANError.java +++ b/android-networking/src/main/java/com/androidnetworking/error/ANError.java @@ -23,7 +23,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ @SuppressWarnings({"unchecked", "unused"}) public class ANError extends Exception { diff --git a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java index 1229ccc..222b0e3 100644 --- a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java +++ b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonParserFactory.java @@ -31,7 +31,7 @@ import okhttp3.ResponseBody; /** - * Created by amitshekhar on 31/07/16. + * Created by owner on 31/07/16. */ public final class GsonParserFactory extends Parser.Factory { diff --git a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java index 5b0f221..b83adc2 100644 --- a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java +++ b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonRequestBodyParser.java @@ -34,7 +34,7 @@ import okio.Buffer; /** - * Created by amitshekhar on 31/07/16. + * Created by owner on 31/07/16. */ final class GsonRequestBodyParser implements Parser { private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); diff --git a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java index d41df27..973de31 100644 --- a/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java +++ b/android-networking/src/main/java/com/androidnetworking/gsonparserfactory/GsonResponseBodyParser.java @@ -29,7 +29,7 @@ import okhttp3.ResponseBody; /** - * Created by amitshekhar on 31/07/16. + * Created by owner on 31/07/16. */ final class GsonResponseBodyParser implements Parser { private final Gson gson; diff --git a/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java b/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java index bb2453a..1795d01 100644 --- a/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java +++ b/android-networking/src/main/java/com/androidnetworking/interceptors/GzipRequestInterceptor.java @@ -30,7 +30,7 @@ import okio.Okio; /** - * Created by amitshekhar on 02/05/16. + * Created by owner on 02/05/16. */ public class GzipRequestInterceptor implements Interceptor { @Override diff --git a/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java b/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java index 44f5265..de7867b 100644 --- a/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java +++ b/android-networking/src/main/java/com/androidnetworking/interceptors/HttpLoggingInterceptor.java @@ -41,7 +41,7 @@ import static okhttp3.internal.platform.Platform.INFO; /** - * Created by amitshekhar on 31/01/17. + * Created by owner on 31/01/17. */ public class HttpLoggingInterceptor implements Interceptor { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java index 54aa9f2..8ca0e45 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/AnalyticsListener.java @@ -18,7 +18,7 @@ package com.androidnetworking.interfaces; /** - * Created by amitshekhar on 31/05/16. + * Created by owner on 31/05/16. */ public interface AnalyticsListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java index 6cdc307..5aa537a 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/BitmapRequestListener.java @@ -22,7 +22,7 @@ import com.androidnetworking.error.ANError; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface BitmapRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java index 05c3bc3..b654a76 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/ConnectionQualityChangeListener.java @@ -20,7 +20,7 @@ import com.androidnetworking.common.ConnectionQuality; /** - * Created by amitshekhar on 29/05/16. + * Created by owner on 29/05/16. */ public interface ConnectionQualityChangeListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java index 1915a00..b4225bc 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadListener.java @@ -20,7 +20,7 @@ import com.androidnetworking.error.ANError; /** - * Created by amitshekhar on 29/04/16. + * Created by owner on 29/04/16. */ public interface DownloadListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java index 4406ee9..d63c7ef 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/DownloadProgressListener.java @@ -18,7 +18,7 @@ package com.androidnetworking.interfaces; /** - * Created by amitshekhar on 30/03/16. + * Created by owner on 30/03/16. */ public interface DownloadProgressListener { void onProgress(long bytesDownloaded, long totalBytes); diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java index e20e913..51f394b 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONArrayRequestListener.java @@ -22,7 +22,7 @@ import org.json.JSONArray; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface JSONArrayRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java index d1b7981..82eb47c 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/JSONObjectRequestListener.java @@ -22,7 +22,7 @@ import org.json.JSONObject; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface JSONObjectRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java index 2df552e..4994554 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndBitmapRequestListener.java @@ -26,7 +26,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface OkHttpResponseAndBitmapRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java index 02b915e..7c95e42 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONArrayRequestListener.java @@ -26,7 +26,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface OkHttpResponseAndJSONArrayRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java index 093e0cb..292a64a 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndJSONObjectRequestListener.java @@ -26,7 +26,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface OkHttpResponseAndJSONObjectRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java index 8b8a744..e487e7e 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndParsedRequestListener.java @@ -24,7 +24,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 31/07/16. + * Created by owner on 31/07/16. */ public interface OkHttpResponseAndParsedRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java index ba83d7e..bc7973e 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseAndStringRequestListener.java @@ -24,7 +24,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface OkHttpResponseAndStringRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java index 448db93..0c6a26a 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/OkHttpResponseListener.java @@ -24,7 +24,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 22/08/16. + * Created by owner on 22/08/16. */ public interface OkHttpResponseListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java index bea5f49..197f447 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/ParsedRequestListener.java @@ -22,7 +22,7 @@ import com.androidnetworking.error.ANError; /** - * Created by amitshekhar on 31/07/16. + * Created by owner on 31/07/16. */ public interface ParsedRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java b/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java index 19e12dd..c980779 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/Parser.java @@ -27,7 +27,7 @@ import okhttp3.ResponseBody; /** - * Created by amitshekhar on 31/07/16. + * Created by owner on 31/07/16. */ public interface Parser { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java index 8d644d4..9432d5d 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/StringRequestListener.java @@ -20,7 +20,7 @@ import com.androidnetworking.error.ANError; /** - * Created by amitshekhar on 23/05/16. + * Created by owner on 23/05/16. */ public interface StringRequestListener { diff --git a/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java b/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java index 4c2a2e1..e6aa12c 100644 --- a/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java +++ b/android-networking/src/main/java/com/androidnetworking/interfaces/UploadProgressListener.java @@ -18,7 +18,7 @@ package com.androidnetworking.interfaces; /** - * Created by amitshekhar on 21/04/16. + * Created by owner on 21/04/16. */ public interface UploadProgressListener { void onProgress(long bytesUploaded, long totalBytes); diff --git a/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java b/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java index d278d54..b1c0a01 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/ANImageLoader.java @@ -33,7 +33,7 @@ import java.util.LinkedList; /** - * Created by amitshekhar on 23/03/16. + * Created by owner on 23/03/16. */ public class ANImageLoader { diff --git a/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java b/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java index b2cd8a6..b7e9a62 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/ANRequestQueue.java @@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicInteger; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class ANRequestQueue { diff --git a/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java b/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java index 5951ef6..4646635 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/DownloadProgressHandler.java @@ -26,7 +26,7 @@ import com.androidnetworking.model.Progress; /** - * Created by amitshekhar on 24/05/16. + * Created by owner on 24/05/16. */ public class DownloadProgressHandler extends Handler { diff --git a/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java b/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java index ee7cfb0..6726570 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/InternalNetworking.java @@ -18,7 +18,7 @@ package com.androidnetworking.internal; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ import android.content.Context; diff --git a/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java b/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java index b784b9c..33a03fe 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/InternalRunnable.java @@ -33,7 +33,7 @@ import static com.androidnetworking.common.RequestType.SIMPLE; /** - * Created by amitshekhar on 22/03/16. + * Created by owner on 22/03/16. */ public class InternalRunnable implements Runnable { diff --git a/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java b/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java index 7e4f61c..213c61d 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/RequestProgressBody.java @@ -32,7 +32,7 @@ import okio.Sink; /** - * Created by amitshekhar on 21/04/16. + * Created by owner on 21/04/16. */ public class RequestProgressBody extends RequestBody { private final RequestBody requestBody; diff --git a/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java b/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java index f1dfc97..5f0d260 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/ResponseProgressBody.java @@ -32,7 +32,7 @@ import okio.Source; /** - * Created by amitshekhar on 24/05/16. + * Created by owner on 24/05/16. */ public class ResponseProgressBody extends ResponseBody { diff --git a/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java b/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java index 9dd8101..b85e1f6 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/SynchronousCall.java @@ -34,7 +34,7 @@ import static com.androidnetworking.common.RequestType.SIMPLE; /** - * Created by amitshekhar on 14/09/16. + * Created by owner on 14/09/16. */ @SuppressWarnings("unchecked") public final class SynchronousCall { diff --git a/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java b/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java index e19f7f0..03924fc 100644 --- a/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java +++ b/android-networking/src/main/java/com/androidnetworking/internal/UploadProgressHandler.java @@ -26,7 +26,7 @@ import com.androidnetworking.model.Progress; /** - * Created by amitshekhar on 24/05/16. + * Created by owner on 24/05/16. */ public class UploadProgressHandler extends Handler { diff --git a/android-networking/src/main/java/com/androidnetworking/model/Progress.java b/android-networking/src/main/java/com/androidnetworking/model/Progress.java index d9c615d..3384c95 100644 --- a/android-networking/src/main/java/com/androidnetworking/model/Progress.java +++ b/android-networking/src/main/java/com/androidnetworking/model/Progress.java @@ -20,7 +20,7 @@ import java.io.Serializable; /** - * Created by amitshekhar on 24/05/16. + * Created by owner on 24/05/16. */ public class Progress implements Serializable { diff --git a/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java b/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java index ec6acf4..61b385f 100644 --- a/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java +++ b/android-networking/src/main/java/com/androidnetworking/utils/ParseUtil.java @@ -24,7 +24,7 @@ import com.google.gson.Gson; /** - * Created by amitshekhar on 15/09/16. + * Created by owner on 15/09/16. */ public class ParseUtil { diff --git a/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java b/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java index eaf268a..7643942 100644 --- a/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java +++ b/android-networking/src/main/java/com/androidnetworking/utils/SourceCloseUtil.java @@ -25,7 +25,7 @@ import okhttp3.Response; /** - * Created by amitshekhar on 15/09/16. + * Created by owner on 15/09/16. */ public final class SourceCloseUtil { diff --git a/android-networking/src/main/java/com/androidnetworking/utils/Utils.java b/android-networking/src/main/java/com/androidnetworking/utils/Utils.java index 416e978..79c171c 100644 --- a/android-networking/src/main/java/com/androidnetworking/utils/Utils.java +++ b/android-networking/src/main/java/com/androidnetworking/utils/Utils.java @@ -43,7 +43,7 @@ import okio.Okio; /** - * Created by amitshekhar on 25/03/16. + * Created by owner on 25/03/16. */ public class Utils { diff --git a/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java b/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java index bef56a5..70f8470 100644 --- a/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java +++ b/android-networking/src/main/java/com/androidnetworking/widget/ANImageView.java @@ -27,7 +27,7 @@ import com.androidnetworking.internal.ANImageLoader; /** - * Created by amitshekhar on 23/03/16. + * Created by owner on 23/03/16. */ public class ANImageView extends ImageView { diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 6b7a2bf..ab6c072 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified -# in /Users/amitshekhar/Library/Android/sdk/tools/proguard/proguard-android.txt +# in /Users/owner/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # diff --git a/app/src/main/java/com/rxjava2/android/samples/model/ApiUser.java b/app/src/main/java/com/rxjava2/android/samples/model/ApiUser.java index 09039ef..70cbd48 100644 --- a/app/src/main/java/com/rxjava2/android/samples/model/ApiUser.java +++ b/app/src/main/java/com/rxjava2/android/samples/model/ApiUser.java @@ -1,7 +1,7 @@ package com.rxjava2.android.samples.model; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class ApiUser { public long id; diff --git a/app/src/main/java/com/rxjava2/android/samples/model/Car.java b/app/src/main/java/com/rxjava2/android/samples/model/Car.java index e223650..a328a28 100644 --- a/app/src/main/java/com/rxjava2/android/samples/model/Car.java +++ b/app/src/main/java/com/rxjava2/android/samples/model/Car.java @@ -6,7 +6,7 @@ import io.reactivex.ObservableSource; /** - * Created by amitshekhar on 30/08/16. + * Created by owner on 30/08/16. */ public class Car { diff --git a/app/src/main/java/com/rxjava2/android/samples/model/Events.java b/app/src/main/java/com/rxjava2/android/samples/model/Events.java index d4541b4..a60da5d 100644 --- a/app/src/main/java/com/rxjava2/android/samples/model/Events.java +++ b/app/src/main/java/com/rxjava2/android/samples/model/Events.java @@ -1,7 +1,7 @@ package com.rxjava2.android.samples.model; /** - * Created by amitshekhar on 06/02/17. + * Created by owner on 06/02/17. */ public class Events { diff --git a/app/src/main/java/com/rxjava2/android/samples/model/User.java b/app/src/main/java/com/rxjava2/android/samples/model/User.java index bb11397..18c0ba7 100644 --- a/app/src/main/java/com/rxjava2/android/samples/model/User.java +++ b/app/src/main/java/com/rxjava2/android/samples/model/User.java @@ -1,7 +1,7 @@ package com.rxjava2.android.samples.model; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class User { public long id; diff --git a/app/src/main/java/com/rxjava2/android/samples/model/UserDetail.java b/app/src/main/java/com/rxjava2/android/samples/model/UserDetail.java index 1be734b..c9d9343 100644 --- a/app/src/main/java/com/rxjava2/android/samples/model/UserDetail.java +++ b/app/src/main/java/com/rxjava2/android/samples/model/UserDetail.java @@ -1,7 +1,7 @@ package com.rxjava2.android.samples.model; /** - * Created by amitshekhar on 04/02/17. + * Created by owner on 04/02/17. */ public class UserDetail { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java index 17a425a..353d8a4 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/networking/NetworkingActivity.java @@ -28,7 +28,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 04/02/17. + * Created by owner on 04/02/17. */ public class NetworkingActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/AsyncSubjectExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/AsyncSubjectExampleActivity.java index 501bc63..2bebfab 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/AsyncSubjectExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/AsyncSubjectExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.subjects.AsyncSubject; /** - * Created by amitshekhar on 17/12/16. + * Created by owner on 17/12/16. */ public class AsyncSubjectExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/BehaviorSubjectExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/BehaviorSubjectExampleActivity.java index e398fd8..eca9617 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/BehaviorSubjectExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/BehaviorSubjectExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.subjects.BehaviorSubject; /** - * Created by amitshekhar on 17/12/16. + * Created by owner on 17/12/16. */ public class BehaviorSubjectExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/BufferExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/BufferExampleActivity.java index ead4b70..be79a43 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/BufferExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/BufferExampleActivity.java @@ -17,7 +17,7 @@ import io.reactivex.disposables.Disposable; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class BufferExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/CompletableObserverExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/CompletableObserverExampleActivity.java index 1f7451a..d05b6bd 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/CompletableObserverExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/CompletableObserverExampleActivity.java @@ -19,7 +19,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class CompletableObserverExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ConcatExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ConcatExampleActivity.java index ce4a3f5..5853c61 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ConcatExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ConcatExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.disposables.Disposable; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class ConcatExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DebounceExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DebounceExampleActivity.java index d0f9802..a9fb625 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DebounceExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DebounceExampleActivity.java @@ -21,7 +21,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 22/12/16. + * Created by owner on 22/12/16. */ public class DebounceExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DeferExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DeferExampleActivity.java index 4aed8c6..8597bbe 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DeferExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DeferExampleActivity.java @@ -16,7 +16,7 @@ import io.reactivex.disposables.Disposable; /** - * Created by amitshekhar on 30/08/16. + * Created by owner on 30/08/16. */ public class DeferExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DelayExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DelayExampleActivity.java index 2979e75..3e025ee 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DelayExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DelayExampleActivity.java @@ -19,7 +19,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 05/03/17. + * Created by owner on 05/03/17. */ public class DelayExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DisposableExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DisposableExampleActivity.java index 2dd124b..f7ac88c 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/DisposableExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/DisposableExampleActivity.java @@ -21,7 +21,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class DisposableExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/FilterExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/FilterExampleActivity.java index e470182..3061256 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/FilterExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/FilterExampleActivity.java @@ -17,7 +17,7 @@ /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class FilterExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/FlowableExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/FlowableExampleActivity.java index 7303cc2..1f9600e 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/FlowableExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/FlowableExampleActivity.java @@ -16,7 +16,7 @@ import io.reactivex.functions.BiFunction; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class FlowableExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/IntervalExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/IntervalExampleActivity.java index 22469be..46e1523 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/IntervalExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/IntervalExampleActivity.java @@ -19,7 +19,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class IntervalExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/MapExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/MapExampleActivity.java index ccc6ace..fec5474 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/MapExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/MapExampleActivity.java @@ -25,7 +25,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class MapExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/MergeExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/MergeExampleActivity.java index 0cd7487..99640c9 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/MergeExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/MergeExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.disposables.Disposable; /** - * Created by amitshekhar on 28/08/16. + * Created by owner on 28/08/16. */ public class MergeExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/PublishSubjectExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/PublishSubjectExampleActivity.java index af8822c..194d717 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/PublishSubjectExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/PublishSubjectExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.subjects.PublishSubject; /** - * Created by amitshekhar on 17/12/16. + * Created by owner on 17/12/16. */ public class PublishSubjectExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReduceExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReduceExampleActivity.java index 1ab9930..b2dd6de 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReduceExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReduceExampleActivity.java @@ -16,7 +16,7 @@ import io.reactivex.functions.BiFunction; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class ReduceExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplayExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplayExampleActivity.java index 8880ea9..1b4257c 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplayExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplayExampleActivity.java @@ -16,7 +16,7 @@ import io.reactivex.subjects.PublishSubject; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class ReplayExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplaySubjectExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplaySubjectExampleActivity.java index 7f09563..94f178b 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplaySubjectExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ReplaySubjectExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.subjects.ReplaySubject; /** - * Created by amitshekhar on 17/12/16. + * Created by owner on 17/12/16. */ public class ReplaySubjectExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java index 3d4e9f1..30f6715 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SimpleExampleActivity.java @@ -17,7 +17,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class SimpleExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SingleObserverExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SingleObserverExampleActivity.java index 6c9ce7c..3e0673f 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SingleObserverExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SingleObserverExampleActivity.java @@ -15,7 +15,7 @@ import io.reactivex.disposables.Disposable; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class SingleObserverExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SkipExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SkipExampleActivity.java index 26706ea..6ffbc83 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/SkipExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/SkipExampleActivity.java @@ -17,7 +17,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class SkipExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/TakeExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/TakeExampleActivity.java index ae71924..19c872f 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/TakeExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/TakeExampleActivity.java @@ -17,7 +17,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class TakeExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ThrottleLastExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ThrottleLastExampleActivity.java index 95b6a45..f79a154 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ThrottleLastExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ThrottleLastExampleActivity.java @@ -21,7 +21,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 22/12/16. + * Created by owner on 22/12/16. */ public class ThrottleLastExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/TimerExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/TimerExampleActivity.java index 17f6369..c6c0dad 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/TimerExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/TimerExampleActivity.java @@ -19,7 +19,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class TimerExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java index a6ed6f2..8d32533 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/operators/ZipExampleActivity.java @@ -24,7 +24,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class ZipExampleActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java index b68b312..f248f79 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationActivity.java @@ -25,7 +25,7 @@ import io.reactivex.processors.PublishProcessor; /** - * Created by amitshekhar on 15/03/17. + * Created by owner on 15/03/17. */ public class PaginationActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationAdapter.java b/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationAdapter.java index 9c9d162..e711081 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationAdapter.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/pagination/PaginationAdapter.java @@ -12,7 +12,7 @@ import java.util.List; /** - * Created by amitshekhar on 15/03/17. + * Created by owner on 15/03/17. */ public class PaginationAdapter extends RecyclerView.Adapter { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBus.java b/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBus.java index cdc81b0..effb090 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBus.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBus.java @@ -4,7 +4,7 @@ import io.reactivex.subjects.PublishSubject; /** - * Created by amitshekhar on 06/02/17. + * Created by owner on 06/02/17. */ public class RxBus { diff --git a/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBusActivity.java b/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBusActivity.java index 2911b42..06e6d3e 100644 --- a/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBusActivity.java +++ b/app/src/main/java/com/rxjava2/android/samples/ui/rxbus/RxBusActivity.java @@ -16,7 +16,7 @@ import io.reactivex.schedulers.Schedulers; /** - * Created by amitshekhar on 06/02/17. + * Created by owner on 06/02/17. */ public class RxBusActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/rxjava2/android/samples/utils/AppConstant.java b/app/src/main/java/com/rxjava2/android/samples/utils/AppConstant.java index 4a8b40f..d1d9f2f 100644 --- a/app/src/main/java/com/rxjava2/android/samples/utils/AppConstant.java +++ b/app/src/main/java/com/rxjava2/android/samples/utils/AppConstant.java @@ -1,7 +1,7 @@ package com.rxjava2.android.samples.utils; /** - * Created by amitshekhar on 30/08/16. + * Created by owner on 30/08/16. */ public final class AppConstant { diff --git a/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java b/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java index e45171d..35b94f9 100644 --- a/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java +++ b/app/src/main/java/com/rxjava2/android/samples/utils/Utils.java @@ -10,7 +10,7 @@ import java.util.List; /** - * Created by amitshekhar on 27/08/16. + * Created by owner on 27/08/16. */ public class Utils { diff --git a/rx2-android-networking/proguard-rules.pro b/rx2-android-networking/proguard-rules.pro index 6b7a2bf..ab6c072 100644 --- a/rx2-android-networking/proguard-rules.pro +++ b/rx2-android-networking/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified -# in /Users/amitshekhar/Library/Android/sdk/tools/proguard/proguard-android.txt +# in /Users/owner/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java index c044dc8..daed073 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetJSONApiTest.java @@ -43,7 +43,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 30/04/17. + * Created by owner on 30/04/17. */ public class Rx2GetJSONApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java index e5461d4..37ba8a1 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetObjectApiTest.java @@ -42,7 +42,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 26/04/17. + * Created by owner on 26/04/17. */ public class Rx2GetObjectApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java index 4f8ba77..d9c185c 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2GetStringApiTest.java @@ -40,7 +40,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 22/04/17. + * Created by owner on 22/04/17. */ public class Rx2GetStringApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java index bdddbcc..ac433be 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartJSONApiTest.java @@ -43,7 +43,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 03/05/17. + * Created by owner on 03/05/17. */ public class Rx2MultipartJSONApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java index ae74aa5..08ae9e9 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartObjectApiTest.java @@ -42,7 +42,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 29/04/17. + * Created by owner on 29/04/17. */ public class Rx2MultipartObjectApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java index dc9fb6e..d559538 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2MultipartStringApiTest.java @@ -40,7 +40,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 25/04/17. + * Created by owner on 25/04/17. */ public class Rx2MultipartStringApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java index b3caebc..93b065c 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostJSONApiTest.java @@ -43,7 +43,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 02/05/17. + * Created by owner on 02/05/17. */ public class Rx2PostJSONApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java index 544f494..4b02b61 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostObjectApiTest.java @@ -42,7 +42,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 28/04/17. + * Created by owner on 28/04/17. */ public class Rx2PostObjectApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java index 3ba9f0d..947530e 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/Rx2PostStringApiTest.java @@ -40,7 +40,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; /** - * Created by amitshekhar on 24/04/17. + * Created by owner on 24/04/17. */ public class Rx2PostStringApiTest extends ApplicationTestCase { diff --git a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java index 4c91f7b..f4c01fa 100644 --- a/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java +++ b/rx2-android-networking/src/androidTest/java/com/rx2androidnetworking/model/User.java @@ -20,7 +20,7 @@ package com.rx2androidnetworking.model; /** - * Created by amitshekhar on 26/04/17. + * Created by owner on 26/04/17. */ public class User { diff --git a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java index 0d8c4d8..161994a 100644 --- a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java +++ b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2ANRequest.java @@ -36,7 +36,7 @@ import io.reactivex.Observable; /** - * Created by Prashant Gupta on 30-01-2017. + * Created by owner on 30-01-2017. */ @SuppressWarnings({"unchecked", "unused"}) public class Rx2ANRequest extends ANRequest { diff --git a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java index 15d62c8..9e64ba1 100644 --- a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java +++ b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2AndroidNetworking.java @@ -20,7 +20,7 @@ package com.rx2androidnetworking; /** - * Created by amitshekhar on 30/01/17. + * Created by owner on 30/01/17. */ /** diff --git a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java index 4d8a373..f9030ec 100644 --- a/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java +++ b/rx2-android-networking/src/main/java/com/rx2androidnetworking/Rx2InternalNetworking.java @@ -55,7 +55,7 @@ import static com.androidnetworking.common.Method.PUT; /** - * Created by Prashant Gupta on 30-01-2017. + * Created by owner on 30-01-2017. */ @SuppressWarnings("unchecked") public class Rx2InternalNetworking {