├── .editorconfig
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── RELEASING.md
├── app-kotlin
├── .gitignore
├── build.gradle
├── detekt.yml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── kotlin
│ └── com
│ │ └── github
│ │ └── pwittchen
│ │ └── reactivenetwork
│ │ └── kotlinapp
│ │ └── MainActivity.kt
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── github
│ │ └── pwittchen
│ │ └── reactivenetwork
│ │ └── app
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── codecov.yml
├── config
├── quality.gradle
└── quality
│ ├── checkstyle
│ ├── checkstyle.xml
│ └── suppressions.xml
│ ├── findbugs
│ └── findbugs-filter.xml
│ ├── lint
│ └── lint.xml
│ └── pmd
│ └── pmd-ruleset.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jetbrains_logo.png
├── library
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── github
│ │ └── pwittchen
│ │ └── reactivenetwork
│ │ └── library
│ │ └── rx2
│ │ ├── Connectivity.java
│ │ ├── ConnectivityPredicate.java
│ │ ├── Preconditions.java
│ │ ├── ReactiveNetwork.java
│ │ ├── internet
│ │ └── observing
│ │ │ ├── InternetObservingSettings.java
│ │ │ ├── InternetObservingStrategy.java
│ │ │ ├── error
│ │ │ ├── DefaultErrorHandler.java
│ │ │ └── ErrorHandler.java
│ │ │ └── strategy
│ │ │ ├── SocketInternetObservingStrategy.java
│ │ │ └── WalledGardenInternetObservingStrategy.java
│ │ └── network
│ │ └── observing
│ │ ├── NetworkObservingStrategy.java
│ │ └── strategy
│ │ ├── LollipopNetworkObservingStrategy.java
│ │ ├── MarshmallowNetworkObservingStrategy.java
│ │ └── PreLollipopNetworkObservingStrategy.java
│ └── test
│ ├── java
│ └── com
│ │ └── github
│ │ └── pwittchen
│ │ └── reactivenetwork
│ │ └── library
│ │ └── rx2
│ │ ├── ConnectivityTest.java
│ │ ├── PreconditionsTest.java
│ │ ├── ReactiveNetworkTest.java
│ │ ├── internet
│ │ └── observing
│ │ │ ├── InternetObservingSettingsTest.java
│ │ │ ├── error
│ │ │ └── DefaultErrorHandlerTest.java
│ │ │ └── strategy
│ │ │ ├── SocketInternetObservingStrategyTest.java
│ │ │ └── WalledGardenInternetObservingStrategyTest.java
│ │ └── network
│ │ └── observing
│ │ ├── NetworkObservingStrategyTest.java
│ │ └── strategy
│ │ ├── LollipopNetworkObservingStrategyTest.java
│ │ ├── MarshmallowNetworkObservingStrategyTest.java
│ │ └── PreLollipopNetworkObservingStrategyTest.java
│ └── resources
│ └── robolectric.properties
├── maven_push.gradle
├── release.sh
├── settings.gradle
├── update_docs.sh
└── update_javadocs.sh
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{kt,kts}]
2 | # possible values: number (e.g. 2), "unset" (makes ktlint ignore indentation completely)
3 | indent_size=2
4 | # possible values: number (e.g. 2), "unset"
5 | continuation_indent_size=2
6 | # true (recommended) / false
7 | insert_final_newline=unset
8 | # possible values: number (e.g. 120) (package name, imports & comments are ignored), "off"
9 | # it's automatically set to 100 on `ktlint --android ...` (per Android Kotlin Style Guide)
10 | max_line_length=off
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [pwittchen]
2 | custom: ['https://paypal.me/pwittchen']
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | or create a failing unit test (recommended)
18 |
19 | **Expected behavior**
20 | A clear and concise description of what you expected to happen.
21 |
22 | **Screenshots**
23 | If applicable, add screenshots to help explain your problem.
24 |
25 | **Smartphone (please complete the following information):**
26 | - Device: [e.g. Google Pixel 2]
27 | - OS: [e.g. Android 9]
28 | - Library Version: [e.g. 3.0.0]
29 |
30 | **Additional context**
31 | Add any other context about the problem here.
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /local.properties
3 | /.idea
4 | /.DS_Store
5 | /build
6 | *.iml
7 | .gradletasknamecach
8 | *.exec
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 |
3 | android:
4 | components:
5 | - tools
6 | - platform-tools
7 | - build-tools-28
8 | - android-28
9 | - extra-android-support
10 | - extra-android-m2repository
11 | licenses:
12 | - android-sdk-license-5be876d5
13 | - android-sdk-license-c81a61d9
14 | - 'android-sdk-preview-license-.+'
15 | - 'android-sdk-license-.+'
16 | - 'google-gdk-license-.+'
17 |
18 | jdk: oraclejdk8
19 |
20 | before_install:
21 | - yes | sdkmanager "platforms;android-27"
22 |
23 | install:
24 | - true
25 |
26 | after_success:
27 | - bash <(curl -s https://codecov.io/bash)
28 |
29 | script:
30 | - ./gradlew clean build test jacocoTestReport check
31 |
32 | cache:
33 | directories:
34 | - $HOME/.m2
35 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at piotr@wittchen.biz.pl. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing guidelines
2 | =======================
3 |
4 | Looking for help?
5 | -----------------
6 |
7 | You have the following options:
8 | - Check out documentation in `README.md` file and read it carefully. It covers almost everything what is important.
9 | - Browse JavaDoc at http://pwittchen.github.io/ReactiveNetwork/
10 | - [Ask the question on StackOverlow](http://stackoverflow.com/questions/ask?tags=reactivenetwork).
11 | - Provide detailed information about your problem and environment and then ask the question in the new GitHub issue here.
12 |
13 | Found a bug?
14 | ------------
15 |
16 | Provide detailed steps to reproduce and make sure this bug is not related to your custom project or environment.
17 | Ideally, create Pull Request with failing unit test (or more tests).
18 |
19 | Want a few feature or improvement?
20 | ----------------------------------
21 |
22 | This is tiny library, so I would avoid overcomplicating it, but if you think a new feature
23 | would be useful and make this project better, then create a new issue.
24 | After that, we can discuss it and work on a Pull Request.
25 |
26 | Want to create a Pull Request?
27 | ------------------------------
28 |
29 | Before creating new Pull Request, please create a new issue and discuss the problem.
30 | If we agree that PR will be reasonable solution, then fork repository, create a separate branch
31 | and work on a feature or bug-fix on this branch. When you're done, make sure that project passes
32 | static code analysis verification with `./gradlew check` command. Moreover, format your code according to
33 | [SquareAndroid](https://github.com/square/java-code-styles) Java Code Styles.
34 | When you performed more commits than one, squash them into one within a single PR (you can use http://rebaseandsqua.sh/ website).
35 | Make sure that your commit message is descriptive enough. If not, then use `git commit --amend` command and change it.
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | This PR introduces the following update:
2 |
3 | [briefly describe your update, e.g. closes specified issue, fixes a bug, adds new unit test, etc.]
4 |
--------------------------------------------------------------------------------
/RELEASING.md:
--------------------------------------------------------------------------------
1 | Releasing Guidelines
2 | ====================
3 |
4 | In order to release new version of the library, we need to perform the following operations:
5 | - create new release issue on GitHub
6 | - prepare release notes and put them to the issue
7 | - update javaDocs by running `./update_javadocs.sh` script
8 | - verify, commit and push changes to `gh-pages` branch
9 | - checkout to the appropriate branch (`RxJava1.x` or `RxJava2.x`)
10 | - bump library version (`VERSION_NAME` and `VERSION_CODE`) in `gradle.properties` file
11 | - commit and push the changes
12 | - run command: `./release.sh`
13 | - wait for the Maven Sync (up to 48 hours)
14 | - when sync is done, checkout to the `RxJava2.x` branch
15 | - update `CHANGELOG.md` file with new release version, current date and release notes
16 | - update website with docs by running `./update_docs.sh` script and push the changes
17 | - create new tagged GitHub release with name the same as `VERSION_NAME` from `gradle.properties` and release notes
18 |
--------------------------------------------------------------------------------
/app-kotlin/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app-kotlin/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'io.gitlab.arturbosch.detekt'
5 |
6 | android {
7 | compileSdkVersion rootProject.ext.compileSdkVersion
8 | buildToolsVersion rootProject.ext.buildToolsVersion
9 |
10 | defaultConfig {
11 | multiDexEnabled true
12 | applicationId "com.github.pwittchen.reactivenetwork.kotlinapp"
13 | minSdkVersion rootProject.ext.minSdkVersionApps
14 | targetSdkVersion rootProject.ext.compileSdkVersion
15 | versionCode 1
16 | versionName "1.0"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled true
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 |
25 | debug {
26 | minifyEnabled false
27 | }
28 | }
29 |
30 | sourceSets {
31 | main.java.srcDirs += 'src/main/kotlin'
32 | }
33 |
34 | lintOptions {
35 | abortOnError false
36 | }
37 | }
38 |
39 | detekt {
40 | version = rootProject.ext.detektVersion
41 | profile("main") {
42 | input = "$projectDir"
43 | config = "$projectDir/detekt.yml"
44 | filters = ".*test.*,.*/resources/.*,.*/tmp/.*"
45 | }
46 | }
47 |
48 | dependencies {
49 | implementation project(':library')
50 | implementation deps.kotlinstdlib
51 | implementation deps.annotation
52 | implementation deps.appcompat
53 | }
54 |
55 | buildscript {
56 | repositories {
57 | mavenCentral()
58 | google()
59 | maven {
60 | url 'https://plugins.gradle.org/m2/'
61 | }
62 | }
63 |
64 | dependencies {
65 | classpath deps.kotlingradleplugin
66 | classpath deps.detekt
67 | }
68 | }
--------------------------------------------------------------------------------
/app-kotlin/detekt.yml:
--------------------------------------------------------------------------------
1 | autoCorrect: true
2 | failFast: false
3 |
4 | test-pattern: # Configure exclusions for test sources
5 | active: true
6 | patterns: # Test file regexes
7 | - '.*/test/.*'
8 | - '.*Test.kt'
9 | - '.*Spec.kt'
10 | exclude-rule-sets:
11 | - 'comments'
12 | exclude-rules:
13 | - 'NamingRules'
14 | - 'WildcardImport'
15 | - 'MagicNumber'
16 | - 'MaxLineLength'
17 | - 'LateinitUsage'
18 | - 'StringLiteralDuplication'
19 | - 'SpreadOperator'
20 | - 'TooManyFunctions'
21 |
22 | build:
23 | warningThreshold: 5
24 | failThreshold: 10
25 | weights:
26 | complexity: 2
27 | formatting: 1
28 | LongParameterList: 1
29 | comments: 1
30 |
31 | processors:
32 | active: true
33 | exclude:
34 | # - 'FunctionCountProcessor'
35 | # - 'PropertyCountProcessor'
36 | # - 'ClassCountProcessor'
37 | # - 'PackageCountProcessor'
38 | # - 'KtFileCountProcessor'
39 |
40 | console-reports:
41 | active: true
42 | exclude:
43 | # - 'ProjectStatisticsReport'
44 | # - 'ComplexityReport'
45 | # - 'NotificationReport'
46 | # - 'FindingsReport'
47 | # - 'BuildFailureReport'
48 |
49 | output-reports:
50 | active: true
51 | exclude:
52 | # - 'PlainOutputReport'
53 | # - 'XmlOutputReport'
54 |
55 | comments:
56 | active: true
57 | CommentOverPrivateFunction:
58 | active: false
59 | CommentOverPrivateProperty:
60 | active: false
61 | UndocumentedPublicClass:
62 | active: false
63 | searchInNestedClass: true
64 | searchInInnerClass: true
65 | searchInInnerObject: true
66 | searchInInnerInterface: true
67 | UndocumentedPublicFunction:
68 | active: false
69 |
70 | complexity:
71 | active: true
72 | LongParameterList:
73 | active: true
74 | threshold: 5
75 | LongMethod:
76 | active: true
77 | threshold: 20
78 | LargeClass:
79 | active: true
80 | threshold: 150
81 | ComplexInterface:
82 | active: false
83 | threshold: 10
84 | includeStaticDeclarations: false
85 | ComplexMethod:
86 | active: true
87 | threshold: 10
88 | StringLiteralDuplication:
89 | active: false
90 | threshold: 2
91 | ignoreAnnotation: true
92 | excludeStringsWithLessThan5Characters: true
93 | ignoreStringsRegex: '$^'
94 | MethodOverloading:
95 | active: false
96 | threshold: 5
97 | NestedBlockDepth:
98 | active: true
99 | threshold: 3
100 | TooManyFunctions:
101 | active: true
102 | thresholdInFiles: 10
103 | thresholdInClasses: 10
104 | thresholdInInterfaces: 10
105 | thresholdInObjects: 10
106 | thresholdInEnums: 10
107 | ComplexCondition:
108 | active: true
109 | threshold: 3
110 | LabeledExpression:
111 | active: false
112 |
113 | empty-blocks:
114 | active: true
115 | EmptyCatchBlock:
116 | active: true
117 | EmptyClassBlock:
118 | active: true
119 | EmptyDefaultConstructor:
120 | active: true
121 | EmptyDoWhileBlock:
122 | active: true
123 | EmptyElseBlock:
124 | active: true
125 | EmptyFinallyBlock:
126 | active: true
127 | EmptyForBlock:
128 | active: true
129 | EmptyFunctionBlock:
130 | active: true
131 | EmptyIfBlock:
132 | active: true
133 | EmptyInitBlock:
134 | active: true
135 | EmptyKtFile:
136 | active: true
137 | EmptySecondaryConstructor:
138 | active: true
139 | EmptyWhenBlock:
140 | active: true
141 | EmptyWhileBlock:
142 | active: true
143 |
144 | exceptions:
145 | active: true
146 | TooGenericExceptionCaught:
147 | active: true
148 | exceptions:
149 | - ArrayIndexOutOfBoundsException
150 | - Error
151 | - Exception
152 | - IllegalMonitorStateException
153 | - NullPointerException
154 | - IndexOutOfBoundsException
155 | - RuntimeException
156 | - Throwable
157 | ExceptionRaisedInUnexpectedLocation:
158 | active: false
159 | methodNames: 'toString,hashCode,equals,finalize'
160 | TooGenericExceptionThrown:
161 | active: true
162 | exceptions:
163 | - Error
164 | - Exception
165 | - NullPointerException
166 | - Throwable
167 | - RuntimeException
168 | NotImplementedDeclaration:
169 | active: false
170 | PrintStackTrace:
171 | active: false
172 | InstanceOfCheckForException:
173 | active: false
174 | ThrowingExceptionsWithoutMessageOrCause:
175 | active: false
176 | exceptions: 'IllegalArgumentException,IllegalStateException,IOException'
177 | ReturnFromFinally:
178 | active: false
179 | ThrowingExceptionFromFinally:
180 | active: false
181 | ThrowingExceptionInMain:
182 | active: false
183 | RethrowCaughtException:
184 | active: false
185 | ThrowingNewInstanceOfSameException:
186 | active: false
187 | SwallowedException:
188 | active: false
189 |
190 | performance:
191 | active: true
192 | ForEachOnRange:
193 | active: true
194 | SpreadOperator:
195 | active: true
196 | UnnecessaryTemporaryInstantiation:
197 | active: true
198 |
199 | potential-bugs:
200 | active: true
201 | DuplicateCaseInWhenExpression:
202 | active: true
203 | EqualsAlwaysReturnsTrueOrFalse:
204 | active: false
205 | EqualsWithHashCodeExist:
206 | active: true
207 | IteratorNotThrowingNoSuchElementException:
208 | active: false
209 | IteratorHasNextCallsNextMethod:
210 | active: false
211 | UselessPostfixExpression:
212 | active: false
213 | InvalidLoopCondition:
214 | active: false
215 | WrongEqualsTypeParameter:
216 | active: false
217 | ExplicitGarbageCollectionCall:
218 | active: true
219 | LateinitUsage:
220 | active: false
221 | excludeAnnotatedProperties: ""
222 | ignoreOnClassesPattern: ""
223 | UnconditionalJumpStatementInLoop:
224 | active: false
225 | UnreachableCode:
226 | active: true
227 | UnsafeCallOnNullableType:
228 | active: false
229 | UnsafeCast:
230 | active: false
231 |
232 | style:
233 | active: true
234 | CollapsibleIfStatements:
235 | active: false
236 | ReturnCount:
237 | active: true
238 | max: 2
239 | excludedFunctions: "equals"
240 | ThrowsCount:
241 | active: true
242 | max: 2
243 | NewLineAtEndOfFile:
244 | active: true
245 | WildcardImport:
246 | active: true
247 | excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
248 | MaxLineLength:
249 | active: true
250 | maxLineLength: 120
251 | excludePackageStatements: false
252 | excludeImportStatements: false
253 | EqualsNullCall:
254 | active: false
255 | ForbiddenComment:
256 | active: true
257 | values: 'TODO:,FIXME:,STOPSHIP:'
258 | ForbiddenImport:
259 | active: false
260 | imports: ''
261 | FunctionOnlyReturningConstant:
262 | active: false
263 | ignoreOverridableFunction: true
264 | excludedFunctions: 'describeContents'
265 | SpacingBetweenPackageAndImports:
266 | active: false
267 | LoopWithTooManyJumpStatements:
268 | active: false
269 | maxJumpCount: 1
270 | MemberNameEqualsClassName:
271 | active: false
272 | ignoreOverriddenFunction: true
273 | VariableNaming:
274 | active: true
275 | variablePattern: '[a-z][A-Za-z0-9]*'
276 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
277 | VariableMinLength:
278 | active: false
279 | minimumVariableNameLength: 1
280 | VariableMaxLength:
281 | active: false
282 | maximumVariableNameLength: 64
283 | TopLevelPropertyNaming:
284 | active: true
285 | constantPattern: '[A-Z][_A-Z0-9]*'
286 | propertyPattern: '[a-z][A-Za-z\d]*'
287 | privatePropertyPattern: '(_)?[a-z][A-Za-z0-9]*'
288 | ObjectPropertyNaming:
289 | active: true
290 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
291 | PackageNaming:
292 | active: true
293 | packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$'
294 | ClassNaming:
295 | active: true
296 | classPattern: '[A-Z$][a-zA-Z0-9$]*'
297 | EnumNaming:
298 | active: true
299 | enumEntryPattern: '^[A-Z$][a-zA-Z_$]*$'
300 | FunctionNaming:
301 | active: true
302 | functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'
303 | FunctionMaxLength:
304 | active: false
305 | maximumFunctionNameLength: 30
306 | FunctionMinLength:
307 | active: false
308 | minimumFunctionNameLength: 3
309 | ForbiddenClassName:
310 | active: false
311 | forbiddenName: ''
312 | SafeCast:
313 | active: true
314 | UnnecessaryAbstractClass:
315 | active: false
316 | UnnecessaryParentheses:
317 | active: false
318 | UnnecessaryInheritance:
319 | active: false
320 | UtilityClassWithPublicConstructor:
321 | active: false
322 | OptionalAbstractKeyword:
323 | active: true
324 | OptionalWhenBraces:
325 | active: false
326 | OptionalReturnKeyword:
327 | active: false
328 | OptionalUnit:
329 | active: false
330 | ProtectedMemberInFinalClass:
331 | active: false
332 | SerialVersionUIDInSerializableClass:
333 | active: false
334 | MagicNumber:
335 | active: true
336 | ignoreNumbers: '-1,0,1,2'
337 | ignoreHashCodeFunction: false
338 | ignorePropertyDeclaration: false
339 | ignoreConstantDeclaration: true
340 | ignoreCompanionObjectPropertyDeclaration: true
341 | ignoreAnnotation: false
342 | ignoreNamedArgument: true
343 | ignoreEnums: false
344 | ModifierOrder:
345 | active: true
346 | DataClassContainsFunctions:
347 | active: false
348 | conversionFunctionPrefix: 'to'
349 | UseDataClass:
350 | active: false
351 | UnusedImports:
352 | active: false
353 | ExpressionBodySyntax:
354 | active: false
355 | NestedClassesVisibility:
356 | active: false
357 | RedundantVisibilityModifierRule:
358 | active: false
359 |
--------------------------------------------------------------------------------
/app-kotlin/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/piotr/Development/android/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 | -dontwarn com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
19 | -dontwarn io.reactivex.functions.Function
20 | -dontwarn rx.internal.util.**
21 | -dontwarn sun.misc.Unsafe
--------------------------------------------------------------------------------
/app-kotlin/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app-kotlin/src/main/kotlin/com/github/pwittchen/reactivenetwork/kotlinapp/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.kotlinapp
17 |
18 | import android.app.Activity
19 | import android.os.Bundle
20 | import android.util.Log
21 | import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
22 | import io.reactivex.android.schedulers.AndroidSchedulers
23 | import io.reactivex.disposables.Disposable
24 | import io.reactivex.schedulers.Schedulers
25 | import kotlinx.android.synthetic.main.activity_main.connectivity_status
26 | import kotlinx.android.synthetic.main.activity_main.internet_status
27 |
28 | class MainActivity : Activity() {
29 | private var connectivityDisposable: Disposable? = null
30 | private var internetDisposable: Disposable? = null
31 |
32 | companion object {
33 | private val TAG = "ReactiveNetwork"
34 | }
35 |
36 | override fun onCreate(savedInstanceState: Bundle?) {
37 | super.onCreate(savedInstanceState)
38 | setContentView(R.layout.activity_main)
39 | }
40 |
41 | override fun onResume() {
42 | super.onResume()
43 |
44 | connectivityDisposable = ReactiveNetwork.observeNetworkConnectivity(applicationContext)
45 | .subscribeOn(Schedulers.io())
46 | .observeOn(AndroidSchedulers.mainThread())
47 | .subscribe { connectivity ->
48 | Log.d(TAG, connectivity.toString())
49 | val state = connectivity.state()
50 | val name = connectivity.typeName()
51 | connectivity_status.text = String.format("state: %s, typeName: %s", state, name)
52 | }
53 |
54 | internetDisposable = ReactiveNetwork.observeInternetConnectivity()
55 | .subscribeOn(Schedulers.io())
56 | .observeOn(AndroidSchedulers.mainThread())
57 | .subscribe { isConnectedToInternet ->
58 | internet_status.text = isConnectedToInternet.toString()
59 | }
60 | }
61 |
62 | override fun onPause() {
63 | super.onPause()
64 | safelyDispose(connectivityDisposable)
65 | safelyDispose(internetDisposable)
66 | }
67 |
68 | private fun safelyDispose(disposable: Disposable?) {
69 | if (disposable != null && !disposable.isDisposed) {
70 | disposable.dispose()
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
22 |
23 |
33 |
34 |
45 |
46 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 | 16dp
4 | 10dp
5 |
6 |
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ReactiveNetwork
3 | Waiting for connectivity status…
4 | Waiting for Internet status…
5 | Connectivity status:
6 | Internet status:
7 |
8 |
--------------------------------------------------------------------------------
/app-kotlin/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.compileSdkVersion
5 | buildToolsVersion rootProject.ext.buildToolsVersion
6 |
7 | defaultConfig {
8 | multiDexEnabled true
9 | applicationId "com.github.pwittchen.reactivenetwork.app"
10 | minSdkVersion rootProject.ext.minSdkVersionApps
11 | targetSdkVersion rootProject.ext.compileSdkVersion
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled true
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 |
22 | debug {
23 | minifyEnabled false
24 | }
25 | }
26 |
27 | lintOptions {
28 | abortOnError false
29 | }
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation project(':library')
39 | implementation deps.appcompat
40 | }
41 |
42 | buildscript {
43 | repositories {
44 | mavenCentral()
45 | google()
46 | maven {
47 | url 'https://plugins.gradle.org/m2/'
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/piotr/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 | -dontwarn com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
19 | -dontwarn io.reactivex.functions.Function
20 | -dontwarn rx.internal.util.**
21 | -dontwarn sun.misc.Unsafe
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/pwittchen/reactivenetwork/app/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.app;
17 |
18 | import android.app.Activity;
19 | import android.net.NetworkInfo;
20 | import android.os.Bundle;
21 | import android.util.Log;
22 | import android.widget.TextView;
23 | import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork;
24 | import io.reactivex.android.schedulers.AndroidSchedulers;
25 | import io.reactivex.disposables.Disposable;
26 | import io.reactivex.schedulers.Schedulers;
27 |
28 | public class MainActivity extends Activity {
29 | private static final String TAG = "ReactiveNetwork";
30 | private TextView tvConnectivityStatus;
31 | private TextView tvInternetStatus;
32 | private Disposable networkDisposable;
33 | private Disposable internetDisposable;
34 |
35 | @Override protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_main);
38 | tvConnectivityStatus = (TextView) findViewById(R.id.connectivity_status);
39 | tvInternetStatus = (TextView) findViewById(R.id.internet_status);
40 | }
41 |
42 | @Override protected void onResume() {
43 | super.onResume();
44 |
45 | networkDisposable = ReactiveNetwork.observeNetworkConnectivity(getApplicationContext())
46 | .subscribeOn(Schedulers.io())
47 | .observeOn(AndroidSchedulers.mainThread())
48 | .subscribe(connectivity -> {
49 | Log.d(TAG, connectivity.toString());
50 | final NetworkInfo.State state = connectivity.state();
51 | final String name = connectivity.typeName();
52 | tvConnectivityStatus.setText(String.format("state: %s, typeName: %s", state, name));
53 | });
54 |
55 | internetDisposable = ReactiveNetwork.observeInternetConnectivity()
56 | .subscribeOn(Schedulers.io())
57 | .observeOn(AndroidSchedulers.mainThread())
58 | .subscribe(isConnected -> tvInternetStatus.setText(isConnected.toString()));
59 | }
60 |
61 | @Override protected void onPause() {
62 | super.onPause();
63 | safelyDispose(networkDisposable, internetDisposable);
64 | }
65 |
66 | private void safelyDispose(Disposable... disposables) {
67 | for (Disposable subscription : disposables) {
68 | if (subscription != null && !subscription.isDisposed()) {
69 | subscription.dispose();
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
22 |
23 |
33 |
34 |
45 |
46 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 | 16dp
4 | 10dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ReactiveNetwork
3 | Waiting for connectivity status…
4 | Waiting for Internet status…
5 | Connectivity status:
6 | Internet status:
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | apply plugin: 'io.codearte.nexus-staging'
4 |
5 | ext {
6 | minSdkVersion = 14
7 | minSdkVersionApps = 23
8 | compileSdkVersion = 29
9 | buildToolsVersion = '28.0.3'
10 | gradleVersion = '4.6'
11 | kotlinVersion = '1.4.0'
12 | detektVersion = '1.0.0.RC6-1'
13 | }
14 |
15 | ext.deps = [rxjava2 : 'io.reactivex.rxjava2:rxjava:2.2.21',
16 | rxandroid2 : 'io.reactivex.rxjava2:rxandroid:2.1.1',
17 | annotation : 'androidx.annotation:annotation:1.1.0',
18 | appcompat : 'androidx.appcompat:appcompat:1.2.0',
19 | junit : 'junit:junit:4.13',
20 | truth : 'com.google.truth:truth:1.0.1',
21 | robolectric : 'org.robolectric:robolectric:4.9',
22 | mockitocore : 'org.mockito:mockito-core:3.5.2',
23 | nullaway : 'com.uber.nullaway:nullaway:0.8.0',
24 | errorprone : 'com.google.errorprone:error_prone_core:2.3.4',
25 | nopen : 'com.jakewharton.nopen:nopen-annotations:1.0.1',
26 | nopenchecker : 'com.jakewharton.nopen:nopen-checker:1.0.1',
27 | kotlinstdlib : "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion",
28 | kotlingradleplugin: "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion",
29 | detekt : "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detektVersion"]
30 |
31 | buildscript {
32 | repositories {
33 | google()
34 | mavenCentral()
35 | maven {
36 | url 'https://plugins.gradle.org/m2/'
37 | }
38 | }
39 | dependencies {
40 | classpath 'com.android.tools.build:gradle:3.6.4'
41 | classpath('com.hiya:jacoco-android:0.2') {
42 | exclude group: 'org.codehaus.groovy', module: 'groovy-all'
43 | }
44 |
45 | classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.13'
46 | classpath 'net.ltgt.gradle:gradle-apt-plugin:0.21'
47 | classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.22.0"
48 | // NOTE: Do not place your application dependencies here; they belong
49 | // in the individual module build.gradle files
50 | }
51 | }
52 |
53 | allprojects {
54 | repositories {
55 | google()
56 | mavenCentral()
57 | maven {
58 | url 'https://plugins.gradle.org/m2/'
59 | }
60 | }
61 | }
62 |
63 | def getRepositoryUsername() {
64 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
65 | }
66 |
67 | def getRepositoryPassword() {
68 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
69 | }
70 |
71 | nexusStaging {
72 | packageGroup = GROUP //optional if packageGroup == project.getGroup()
73 | stagingProfileId = "9add401d06ecc9" //when not defined will be got from server using "packageGroup"
74 | username = getRepositoryUsername()
75 | password = getRepositoryPassword()
76 | }
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | target: 80%
6 | threshold: 10%
7 |
8 | patch:
9 | default:
10 | target: 80%
11 | threshold: 10%
12 |
13 | changes: no
14 |
--------------------------------------------------------------------------------
/config/quality.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'checkstyle'
2 | apply plugin: 'pmd'
3 |
4 | // Add checkstyle, pmd and lint to the check task.
5 | check.dependsOn 'checkstyle', 'pmd', 'lint'
6 |
7 | checkstyle {
8 | toolVersion = "6.0"
9 | }
10 |
11 | task checkstyle(type: Checkstyle) {
12 | configFile file("${project.rootDir}/config/quality/checkstyle/checkstyle.xml")
13 | configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/quality/checkstyle/suppressions.xml").absolutePath
14 | source 'src'
15 | include '**/*.java'
16 | exclude '**/gen/**'
17 | classpath = files()
18 | }
19 |
20 | task pmd(type: Pmd) {
21 | ignoreFailures = false
22 | ruleSetFiles = files("${project.rootDir}/config/quality/pmd/pmd-ruleset.xml")
23 | ruleSets = []
24 |
25 | source 'src'
26 | include '**/*.java'
27 | exclude '**/gen/**'
28 |
29 | reports {
30 | xml.enabled = false
31 | html.enabled = true
32 | xml {
33 | destination file("$project.buildDir/reports/pmd/pmd.xml")
34 | }
35 | html {
36 | destination file("$project.buildDir/reports/pmd/pmd.html")
37 | }
38 | }
39 | }
40 |
41 | android {
42 | lintOptions {
43 | abortOnError false
44 | xmlReport false
45 | htmlReport true
46 | lintConfig file("${project.rootDir}/config/quality/lint/lint.xml")
47 | htmlOutput file("$project.buildDir/reports/lint/lint-result.html")
48 | xmlOutput file("$project.buildDir/reports/lint/lint-result.xml")
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/config/quality/checkstyle/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/config/quality/checkstyle/suppressions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/config/quality/findbugs/findbugs-filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/config/quality/lint/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/config/quality/pmd/pmd-ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | Custom ruleset for Android application
8 |
9 | .*/R.java
10 | .*/gen/.*
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_NAME=3.0.8
2 | VERSION_CODE=39
3 | GROUP=com.github.pwittchen
4 |
5 | POM_DESCRIPTION=Android library listening network connection state and Internet connectivity with RxJava Observables
6 | POM_URL=https://github.com/pwittchen/ReactiveNetwork
7 | POM_SCM_URL=https://github.com/pwittchen/ReactiveNetwork
8 | POM_SCM_CONNECTION=scm:git@github.com:pwittchen/ReactiveNetwork.git
9 | POM_SCM_DEV_CONNECTION=scm:git@github.com:pwittchen/ReactiveNetwork.git
10 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
11 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
12 | POM_LICENCE_DIST=repo
13 | POM_DEVELOPER_ID=pwittchen
14 | POM_DEVELOPER_NAME=Piotr Wittchen
15 |
16 | org.gradle.daemon=true
17 | org.gradle.jvmargs=-XX:MaxPermSize=1024m -XX:+CMSClassUnloadingEnabled -XX:+HeapDumpOnOutOfMemoryError -Xmx4096m -XX:MaxHeapSize=4048 -Xms1024m
18 |
19 | android.useAndroidX=true
20 | android.enableJetifier=true
21 | android.jetifier.blacklist=bcprov-jdk15on
22 | android.enableR8.fullMode=false
23 | android.enableUnitTestBinaryResources=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin or MSYS, switch paths to Windows format before running java
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=`expr $i + 1`
158 | done
159 | case $i in
160 | 0) set -- ;;
161 | 1) set -- "$args0" ;;
162 | 2) set -- "$args0" "$args1" ;;
163 | 3) set -- "$args0" "$args1" "$args2" ;;
164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=`save "$@"`
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | exec "$JAVACMD" "$@"
184 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto init
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto init
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :init
68 | @rem Get command-line arguments, handling Windows variants
69 |
70 | if not "%OS%" == "Windows_NT" goto win9xME_args
71 |
72 | :win9xME_args
73 | @rem Slurp the command line arguments.
74 | set CMD_LINE_ARGS=
75 | set _SKIP=2
76 |
77 | :win9xME_args_slurp
78 | if "x%~1" == "x" goto execute
79 |
80 | set CMD_LINE_ARGS=%*
81 |
82 | :execute
83 | @rem Setup the command line
84 |
85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
86 |
87 | @rem Execute Gradle
88 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
89 |
90 | :end
91 | @rem End local scope for the variables with windows NT shell
92 | if "%ERRORLEVEL%"=="0" goto mainEnd
93 |
94 | :fail
95 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
96 | rem the _cmd.exe /c_ return code!
97 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
98 | exit /b 1
99 |
100 | :mainEnd
101 | if "%OS%"=="Windows_NT" endlocal
102 |
103 | :omega
104 |
--------------------------------------------------------------------------------
/jetbrains_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwittchen/ReactiveNetwork/ddfde340e4c1f3acb6bfe10b8c3804dd63ae121b/jetbrains_logo.png
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'jacoco'
3 | apply plugin: 'com.hiya.jacoco-android'
4 | apply plugin: 'net.ltgt.errorprone'
5 | apply plugin: 'net.ltgt.apt'
6 | apply from: '../config/quality.gradle'
7 | apply from: '../maven_push.gradle'
8 |
9 | jacoco {
10 | toolVersion = "0.8.4"
11 | }
12 |
13 | android {
14 | compileSdkVersion rootProject.ext.compileSdkVersion
15 | buildToolsVersion rootProject.ext.buildToolsVersion
16 |
17 | defaultConfig {
18 | multiDexEnabled true
19 | minSdkVersion rootProject.ext.minSdkVersion
20 | targetSdkVersion rootProject.ext.compileSdkVersion
21 | versionCode 1
22 | versionName "1.0"
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 | }
30 |
31 | debug {
32 | minifyEnabled false
33 | testCoverageEnabled true
34 | }
35 | }
36 |
37 | compileOptions {
38 | sourceCompatibility JavaVersion.VERSION_1_8
39 | targetCompatibility JavaVersion.VERSION_1_8
40 | }
41 |
42 | packagingOptions {
43 | exclude 'LICENSE.txt'
44 | exclude 'META-INF/LICENSE.txt'
45 | }
46 |
47 | testOptions {
48 | unitTests.all {
49 | jacoco {
50 | includeNoLocationClasses = true
51 | }
52 | systemProperty 'robolectric.dependency.repo.url', 'https://repo1.maven.org/maven2'
53 | }
54 | }
55 |
56 | testOptions.unitTests.includeAndroidResources = true
57 |
58 | jacocoAndroidUnitTestReport {
59 | csv.enabled false
60 | html.enabled true
61 | xml.enabled true
62 | }
63 |
64 | dependencies {
65 | api deps.rxjava2
66 | api deps.rxandroid2
67 | implementation deps.annotation
68 |
69 | testImplementation project(path: ':library')
70 | testImplementation deps.junit
71 | testImplementation deps.truth
72 | testImplementation deps.robolectric
73 | testImplementation deps.mockitocore
74 |
75 | annotationProcessor deps.nullaway
76 |
77 | compileOnly deps.nopen
78 |
79 | errorprone deps.errorprone
80 | errorprone deps.nopenchecker
81 | }
82 |
83 | compileOptions {
84 | sourceCompatibility JavaVersion.VERSION_1_8
85 | targetCompatibility JavaVersion.VERSION_1_8
86 | }
87 |
88 | tasks.withType(JavaCompile) {
89 | if (!name.toLowerCase().contains("test")) {
90 | options.compilerArgs +=
91 | ["-Xep:NullAway:ERROR", "-XepOpt:NullAway:AnnotatedPackages=com.github.pwittchen.reactivenetwork"]
92 | }
93 | }
94 |
95 | tasks.withType(Test) {
96 | jacoco.includeNoLocationClasses = true
97 | jacoco.excludes = ['jdk.internal.*']
98 | }
99 | }
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=reactivenetwork
2 | POM_ARTIFACT_ID=reactivenetwork-rx2
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/piotr/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/Connectivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import android.content.Context;
19 | import android.net.ConnectivityManager;
20 | import android.net.NetworkInfo;
21 | import android.os.Build;
22 | import androidx.annotation.NonNull;
23 | import androidx.annotation.RequiresApi;
24 |
25 | /**
26 | * Connectivity class represents current connectivity status. It wraps NetworkInfo object.
27 | */
28 | @RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
29 | public final class Connectivity {
30 | static final int UNKNOWN_TYPE = -1;
31 | static final int UNKNOWN_SUB_TYPE = -1;
32 | private NetworkInfo.State state; // NOPMD
33 | private NetworkInfo.DetailedState detailedState; // NOPMD
34 | private int type; // NOPMD
35 | private int subType; // NOPMD
36 | private boolean available; // NOPMD
37 | private boolean failover; // NOPMD
38 | private boolean roaming; // NOPMD
39 | private String typeName; // NOPMD
40 | private String subTypeName; // NOPMD
41 | private String reason; // NOPMD
42 | private String extraInfo; // NOPMD
43 |
44 | public static Connectivity create() {
45 | return builder().build();
46 | }
47 |
48 | public static Connectivity create(@NonNull Context context) {
49 | Preconditions.checkNotNull(context, "context == null");
50 | return create(context, getConnectivityManager(context));
51 | }
52 |
53 | private static ConnectivityManager getConnectivityManager(Context context) {
54 | final String service = Context.CONNECTIVITY_SERVICE;
55 | return (ConnectivityManager) context.getSystemService(service);
56 | }
57 |
58 | protected static Connectivity create(@NonNull Context context, ConnectivityManager manager) {
59 | Preconditions.checkNotNull(context, "context == null");
60 |
61 | if (manager == null) {
62 | return create();
63 | }
64 |
65 | final NetworkInfo networkInfo = manager.getActiveNetworkInfo();
66 | return (networkInfo == null) ? create() : create(networkInfo);
67 | }
68 |
69 | private static Connectivity create(NetworkInfo networkInfo) {
70 | return new Builder()
71 | .state(networkInfo.getState())
72 | .detailedState(networkInfo.getDetailedState())
73 | .type(networkInfo.getType())
74 | .subType(networkInfo.getSubtype())
75 | .available(networkInfo.isAvailable())
76 | .failover(networkInfo.isFailover())
77 | .roaming(networkInfo.isRoaming())
78 | .typeName(networkInfo.getTypeName())
79 | .subTypeName(networkInfo.getSubtypeName())
80 | .reason(networkInfo.getReason())
81 | .extraInfo(networkInfo.getExtraInfo())
82 | .build();
83 | }
84 |
85 | private Connectivity(Builder builder) {
86 | state = builder.state;
87 | detailedState = builder.detailedState;
88 | type = builder.type;
89 | subType = builder.subType;
90 | available = builder.available;
91 | failover = builder.failover;
92 | roaming = builder.roaming;
93 | typeName = builder.typeName;
94 | subTypeName = builder.subTypeName;
95 | reason = builder.reason;
96 | extraInfo = builder.extraInfo;
97 | }
98 |
99 | private Connectivity() {
100 | this(builder());
101 | }
102 |
103 | private static Builder builder() {
104 | return new Connectivity.Builder();
105 | }
106 |
107 | public NetworkInfo.State state() {
108 | return state;
109 | }
110 |
111 | public static Builder state(NetworkInfo.State state) {
112 | return builder().state(state);
113 | }
114 |
115 | public NetworkInfo.DetailedState detailedState() {
116 | return detailedState;
117 | }
118 |
119 | public static Builder state(NetworkInfo.DetailedState detailedState) {
120 | return builder().detailedState(detailedState);
121 | }
122 |
123 | public int type() {
124 | return type;
125 | }
126 |
127 | public static Builder type(int type) {
128 | return builder().type(type);
129 | }
130 |
131 | public int subType() {
132 | return subType;
133 | }
134 |
135 | public static Builder subType(int subType) {
136 | return builder().subType(subType);
137 | }
138 |
139 | public boolean available() {
140 | return available;
141 | }
142 |
143 | public static Builder available(boolean available) {
144 | return builder().available(available);
145 | }
146 |
147 | public boolean failover() {
148 | return failover;
149 | }
150 |
151 | public static Builder failover(boolean failover) {
152 | return builder().failover(failover);
153 | }
154 |
155 | public boolean roaming() {
156 | return roaming;
157 | }
158 |
159 | public static Builder roaming(boolean roaming) {
160 | return builder().roaming(roaming);
161 | }
162 |
163 | public String typeName() {
164 | return typeName;
165 | }
166 |
167 | public static Builder typeName(String typeName) {
168 | return builder().typeName(typeName);
169 | }
170 |
171 | public String subTypeName() {
172 | return subTypeName;
173 | }
174 |
175 | public static Builder subTypeName(String subTypeName) {
176 | return builder().subTypeName(subTypeName);
177 | }
178 |
179 | public String reason() {
180 | return reason;
181 | }
182 |
183 | public static Builder reason(String reason) {
184 | return builder().reason(reason);
185 | }
186 |
187 | public String extraInfo() {
188 | return extraInfo;
189 | }
190 |
191 | public static Builder extraInfo(String extraInfo) {
192 | return builder().extraInfo(extraInfo);
193 | }
194 |
195 | @Override public boolean equals(Object o) {
196 | if (this == o) {
197 | return true;
198 | }
199 | if (o == null || getClass() != o.getClass()) {
200 | return false;
201 | }
202 |
203 | Connectivity that = (Connectivity) o;
204 |
205 | if (type != that.type) {
206 | return false;
207 | }
208 | if (subType != that.subType) {
209 | return false;
210 | }
211 | if (available != that.available) {
212 | return false;
213 | }
214 | if (failover != that.failover) {
215 | return false;
216 | }
217 | if (roaming != that.roaming) {
218 | return false;
219 | }
220 | if (state != that.state) {
221 | return false;
222 | }
223 | if (detailedState != that.detailedState) {
224 | return false;
225 | }
226 | if (!typeName.equals(that.typeName)) {
227 | return false;
228 | }
229 | if (subTypeName != null ? !subTypeName.equals(that.subTypeName) : that.subTypeName != null) {
230 | return false;
231 | }
232 | if (reason != null ? !reason.equals(that.reason) : that.reason != null) {
233 | return false;
234 | }
235 |
236 | return extraInfo != null ? extraInfo.equals(that.extraInfo) : that.extraInfo == null;
237 | }
238 |
239 | @Override public int hashCode() {
240 | int result = state.hashCode();
241 | result = 31 * result + (detailedState != null ? detailedState.hashCode() : 0);
242 | result = 31 * result + type;
243 | result = 31 * result + subType;
244 | result = 31 * result + (available ? 1 : 0);
245 | result = 31 * result + (failover ? 1 : 0);
246 | result = 31 * result + (roaming ? 1 : 0);
247 | result = 31 * result + typeName.hashCode();
248 | result = 31 * result + (subTypeName != null ? subTypeName.hashCode() : 0);
249 | result = 31 * result + (reason != null ? reason.hashCode() : 0);
250 | result = 31 * result + (extraInfo != null ? extraInfo.hashCode() : 0);
251 | return result;
252 | }
253 |
254 | @Override public String toString() {
255 | return "Connectivity{"
256 | + "state="
257 | + state
258 | + ", detailedState="
259 | + detailedState
260 | + ", type="
261 | + type
262 | + ", subType="
263 | + subType
264 | + ", available="
265 | + available
266 | + ", failover="
267 | + failover
268 | + ", roaming="
269 | + roaming
270 | + ", typeName='"
271 | + typeName
272 | + '\''
273 | + ", subTypeName='"
274 | + subTypeName
275 | + '\''
276 | + ", reason='"
277 | + reason
278 | + '\''
279 | + ", extraInfo='"
280 | + extraInfo
281 | + '\''
282 | + '}';
283 | }
284 |
285 | public final static class Builder {
286 |
287 | // disabling PMD for builder class attributes
288 | // because we want to have the same method names as names of the attributes for builder
289 |
290 | private NetworkInfo.State state = NetworkInfo.State.DISCONNECTED; // NOPMD
291 | private NetworkInfo.DetailedState detailedState = NetworkInfo.DetailedState.IDLE; // NOPMD
292 | private int type = UNKNOWN_TYPE; // NOPMD
293 | private int subType = UNKNOWN_SUB_TYPE; // NOPMD
294 | private boolean available = false; // NOPMD
295 | private boolean failover = false; // NOPMD
296 | private boolean roaming = false; // NOPMD
297 | private String typeName = "NONE"; // NOPMD
298 | private String subTypeName = "NONE"; // NOPMD
299 | private String reason = ""; // NOPMD
300 | private String extraInfo = ""; // NOPMD
301 |
302 | public Builder state(NetworkInfo.State state) {
303 | this.state = state;
304 | return this;
305 | }
306 |
307 | public Builder detailedState(NetworkInfo.DetailedState detailedState) {
308 | this.detailedState = detailedState;
309 | return this;
310 | }
311 |
312 | public Builder type(int type) {
313 | this.type = type;
314 | return this;
315 | }
316 |
317 | public Builder subType(int subType) {
318 | this.subType = subType;
319 | return this;
320 | }
321 |
322 | public Builder available(boolean available) {
323 | this.available = available;
324 | return this;
325 | }
326 |
327 | public Builder failover(boolean failover) {
328 | this.failover = failover;
329 | return this;
330 | }
331 |
332 | public Builder roaming(boolean roaming) {
333 | this.roaming = roaming;
334 | return this;
335 | }
336 |
337 | public Builder typeName(String name) {
338 | this.typeName = name;
339 | return this;
340 | }
341 |
342 | public Builder subTypeName(String subTypeName) {
343 | this.subTypeName = subTypeName;
344 | return this;
345 | }
346 |
347 | public Builder reason(String reason) {
348 | this.reason = reason;
349 | return this;
350 | }
351 |
352 | public Builder extraInfo(String extraInfo) {
353 | this.extraInfo = extraInfo;
354 | return this;
355 | }
356 |
357 | public Connectivity build() {
358 | return new Connectivity(this);
359 | }
360 | }
361 | }
362 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/ConnectivityPredicate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import android.net.NetworkInfo;
19 |
20 | import io.reactivex.annotations.NonNull;
21 | import io.reactivex.functions.Predicate;
22 |
23 | /**
24 | * ConnectivityPredicate is a class containing predefined methods, which can be used for filtering
25 | * reactive streams of network connectivity
26 | */
27 | public final class ConnectivityPredicate {
28 |
29 | private ConnectivityPredicate() {
30 | }
31 |
32 | /**
33 | * Filter, which returns true if at least one given state occurred
34 | *
35 | * @param states NetworkInfo.State, which can have one or more states
36 | * @return true if at least one given state occurred
37 | */
38 | public static Predicate hasState(final NetworkInfo.State... states) {
39 | return new Predicate() {
40 | @Override public boolean test(@NonNull Connectivity connectivity) throws Exception {
41 | for (NetworkInfo.State state : states) {
42 | if (connectivity.state() == state) {
43 | return true;
44 | }
45 | }
46 | return false;
47 | }
48 | };
49 | }
50 |
51 | /**
52 | * Filter, which returns true if at least one given type occurred
53 | *
54 | * @param types int, which can have one or more types
55 | * @return true if at least one given type occurred
56 | */
57 | public static Predicate hasType(final int... types) {
58 | final int[] extendedTypes = appendUnknownNetworkTypeToTypes(types);
59 | return new Predicate() {
60 | @Override public boolean test(@NonNull Connectivity connectivity) throws Exception {
61 | for (int type : extendedTypes) {
62 | if (connectivity.type() == type) {
63 | return true;
64 | }
65 | }
66 | return false;
67 | }
68 | };
69 | }
70 |
71 | /**
72 | * Returns network types from the input with additional unknown type,
73 | * what helps during connections filtering when device
74 | * is being disconnected from a specific network
75 | *
76 | * @param types of the network as an array of ints
77 | * @return types of the network with unknown type as an array of ints
78 | */
79 | protected static int[] appendUnknownNetworkTypeToTypes(int[] types) {
80 | int i = 0;
81 | final int[] extendedTypes = new int[types.length + 1];
82 | for (int type : types) {
83 | extendedTypes[i] = type;
84 | i++;
85 | }
86 | extendedTypes[i] = Connectivity.UNKNOWN_TYPE;
87 | return extendedTypes;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/Preconditions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import android.os.Build;
19 |
20 | public final class Preconditions {
21 | /**
22 | * Validation method, which checks if an object is null
23 | *
24 | * @param object to verify
25 | * @param message to be thrown in exception
26 | */
27 | public static void checkNotNull(Object object, String message) {
28 | if (object == null) {
29 | throw new IllegalArgumentException(message);
30 | }
31 | }
32 |
33 | /**
34 | * Validation method, which checks if a string is null or empty
35 | *
36 | * @param string to verify
37 | * @param message to be thrown in exception
38 | */
39 | public static void checkNotNullOrEmpty(String string, String message) {
40 | if (string == null || string.isEmpty()) {
41 | throw new IllegalArgumentException(message);
42 | }
43 | }
44 |
45 | /**
46 | * Validation method, which checks is an integer number is positive
47 | *
48 | * @param number integer to verify
49 | * @param message to be thrown in exception
50 | */
51 | public static void checkGreaterOrEqualToZero(int number, String message) {
52 | if (number < 0) {
53 | throw new IllegalArgumentException(message);
54 | }
55 | }
56 |
57 | /**
58 | * Validation method, which checks is an integer number is non-zero or positive
59 | *
60 | * @param number integer to verify
61 | * @param message to be thrown in exception
62 | */
63 | public static void checkGreaterThanZero(int number, String message) {
64 | if (number <= 0) {
65 | throw new IllegalArgumentException(message);
66 | }
67 | }
68 |
69 | /**
70 | * Validation method, which checks if current Android version is at least Lollipop (API 21) or
71 | * higher
72 | *
73 | * @return boolean true if current Android version is Lollipop or higher
74 | */
75 | public static boolean isAtLeastAndroidLollipop() {
76 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
77 | }
78 |
79 | /**
80 | * Validation method, which checks if current Android version is at least Marshmallow (API 23) or
81 | * higher
82 | *
83 | * @return boolean true if current Android version is Marshmallow or higher
84 | */
85 | public static boolean isAtLeastAndroidMarshmallow() {
86 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
87 | }
88 | }
89 |
90 |
91 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/ReactiveNetwork.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import android.Manifest;
19 | import android.content.Context;
20 | import androidx.annotation.RequiresPermission;
21 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings;
22 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy;
23 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
24 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
25 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy.LollipopNetworkObservingStrategy;
26 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy.MarshmallowNetworkObservingStrategy;
27 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy.PreLollipopNetworkObservingStrategy;
28 | import com.jakewharton.nopen.annotation.Open;
29 | import io.reactivex.Observable;
30 | import io.reactivex.Single;
31 |
32 | /**
33 | * ReactiveNetwork is an Android library
34 | * listening network connection state and change of the WiFi signal strength
35 | * with RxJava Observables. It can be easily used with RxAndroid.
36 | */
37 | @Open public class ReactiveNetwork {
38 | public final static String LOG_TAG = "ReactiveNetwork";
39 |
40 | protected ReactiveNetwork() {
41 | }
42 |
43 | /**
44 | * Creates a new instance of the ReactiveNetwork class
45 | *
46 | * @return ReactiveNetwork object
47 | */
48 | public static ReactiveNetwork create() {
49 | return new ReactiveNetwork();
50 | }
51 |
52 | /**
53 | * Observes network connectivity. Information about network state, type and typeName are contained
54 | * in
55 | * observed Connectivity object.
56 | *
57 | * @param context Context of the activity or an application
58 | * @return RxJava Observable with Connectivity class containing information about network state,
59 | * type and typeName
60 | */
61 | @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
62 | public static Observable observeNetworkConnectivity(final Context context) {
63 | final NetworkObservingStrategy strategy;
64 |
65 | if (Preconditions.isAtLeastAndroidMarshmallow()) {
66 | strategy = new MarshmallowNetworkObservingStrategy();
67 | } else if (Preconditions.isAtLeastAndroidLollipop()) {
68 | strategy = new LollipopNetworkObservingStrategy();
69 | } else {
70 | strategy = new PreLollipopNetworkObservingStrategy();
71 | }
72 |
73 | return observeNetworkConnectivity(context, strategy);
74 | }
75 |
76 | /**
77 | * Observes network connectivity. Information about network state, type and typeName are contained
78 | * in observed Connectivity object. Moreover, allows you to define NetworkObservingStrategy.
79 | *
80 | * @param context Context of the activity or an application
81 | * @param strategy NetworkObserving strategy to be applied - you can use one of the existing
82 | * strategies {@link PreLollipopNetworkObservingStrategy},
83 | * {@link LollipopNetworkObservingStrategy} or create your own custom strategy
84 | * @return RxJava Observable with Connectivity class containing information about network state,
85 | * type and typeName
86 | */
87 | @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
88 | public static Observable observeNetworkConnectivity(final Context context,
89 | final NetworkObservingStrategy strategy) {
90 | Preconditions.checkNotNull(context, "context == null");
91 | Preconditions.checkNotNull(strategy, "strategy == null");
92 | return strategy.observeNetworkConnectivity(context);
93 | }
94 |
95 | /**
96 | * Observes connectivity with the Internet with default settings. It pings remote host
97 | * (www.google.com) at port 80 every 2 seconds with 2 seconds of timeout. This operation is used
98 | * for determining if device is connected to the Internet or not. Please note that this method is
99 | * less efficient than {@link #observeNetworkConnectivity(Context)} method and consumes data
100 | * transfer, but it gives you actual information if device is connected to the Internet or not.
101 | *
102 | * @return RxJava Observable with Boolean - true, when we have an access to the Internet
103 | * and false if not
104 | */
105 | @RequiresPermission(Manifest.permission.INTERNET)
106 | public static Observable observeInternetConnectivity() {
107 | InternetObservingSettings settings = InternetObservingSettings.create();
108 | return observeInternetConnectivity(settings.strategy(), settings.initialInterval(),
109 | settings.interval(), settings.host(), settings.port(),
110 | settings.timeout(), settings.httpResponse(), settings.errorHandler());
111 | }
112 |
113 | /**
114 | * Observes connectivity with the Internet in a given time interval.
115 | *
116 | * @param settings Internet Observing Settings created via Builder pattern
117 | * @return RxJava Observable with Boolean - true, when we have connection with host and false if
118 | * not
119 | */
120 | @RequiresPermission(Manifest.permission.INTERNET)
121 | public static Observable observeInternetConnectivity(
122 | InternetObservingSettings settings) {
123 | return observeInternetConnectivity(settings.strategy(), settings.initialInterval(),
124 | settings.interval(), settings.host(), settings.port(),
125 | settings.timeout(), settings.httpResponse(), settings.errorHandler());
126 | }
127 |
128 | /**
129 | * Observes connectivity with the Internet in a given time interval.
130 | *
131 | * @param strategy for observing Internet connectivity
132 | * @param initialIntervalInMs in milliseconds determining the delay of the first connectivity
133 | * check
134 | * @param intervalInMs in milliseconds determining how often we want to check connectivity
135 | * @param host for checking Internet connectivity
136 | * @param port for checking Internet connectivity
137 | * @param timeoutInMs for pinging remote host in milliseconds
138 | * @param httpResponse expected HTTP response code indicating that connection is established
139 | * @param errorHandler for handling errors during connectivity check
140 | * @return RxJava Observable with Boolean - true, when we have connection with host and false if
141 | * not
142 | */
143 | @RequiresPermission(Manifest.permission.INTERNET)
144 | protected static Observable observeInternetConnectivity(
145 | final InternetObservingStrategy strategy, final int initialIntervalInMs,
146 | final int intervalInMs, final String host, final int port, final int timeoutInMs,
147 | final int httpResponse, final ErrorHandler errorHandler) {
148 | checkStrategyIsNotNull(strategy);
149 | return strategy.observeInternetConnectivity(initialIntervalInMs, intervalInMs, host, port,
150 | timeoutInMs, httpResponse, errorHandler);
151 | }
152 |
153 | /**
154 | * Checks connectivity with the Internet. This operation is performed only once.
155 | *
156 | * @return RxJava Single with Boolean - true, when we have an access to the Internet
157 | * and false if not
158 | */
159 | @RequiresPermission(Manifest.permission.INTERNET)
160 | public static Single checkInternetConnectivity() {
161 | InternetObservingSettings settings = InternetObservingSettings.create();
162 | return checkInternetConnectivity(settings.strategy(), settings.host(), settings.port(),
163 | settings.timeout(), settings.httpResponse(), settings.errorHandler());
164 | }
165 |
166 | /**
167 | * Checks connectivity with the Internet. This operation is performed only once.
168 | *
169 | * @param settings Internet Observing Settings created via Builder pattern
170 | * @return RxJava Single with Boolean - true, when we have connection with host and false if
171 | * not
172 | */
173 | @RequiresPermission(Manifest.permission.INTERNET)
174 | public static Single checkInternetConnectivity(InternetObservingSettings settings) {
175 | return checkInternetConnectivity(settings.strategy(), settings.host(), settings.port(),
176 | settings.timeout(), settings.httpResponse(), settings.errorHandler());
177 | }
178 |
179 | /**
180 | * Checks connectivity with the Internet. This operation is performed only once.
181 | *
182 | * @param strategy for observing Internet connectivity
183 | * @param host for checking Internet connectivity
184 | * @param port for checking Internet connectivity
185 | * @param timeoutInMs for pinging remote host in milliseconds
186 | * @param httpResponse expected HTTP response code indicating that connection is established
187 | * @param errorHandler for handling errors during connectivity check
188 | * @return RxJava Single with Boolean - true, when we have connection with host and false if
189 | * not
190 | */
191 | @RequiresPermission(Manifest.permission.INTERNET)
192 | protected static Single checkInternetConnectivity(
193 | final InternetObservingStrategy strategy,
194 | final String host, final int port, final int timeoutInMs, final int httpResponse,
195 | final ErrorHandler errorHandler) {
196 | checkStrategyIsNotNull(strategy);
197 | return strategy.checkInternetConnectivity(host, port, timeoutInMs, httpResponse, errorHandler);
198 | }
199 |
200 | private static void checkStrategyIsNotNull(InternetObservingStrategy strategy) {
201 | Preconditions.checkNotNull(strategy, "strategy == null");
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/InternetObservingSettings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing;
17 |
18 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.DefaultErrorHandler;
19 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
20 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy;
21 | import java.net.HttpURLConnection;
22 |
23 | /**
24 | * Contains state of internet connectivity settings.
25 | * We should use its Builder for creating new settings
26 | */
27 | @SuppressWarnings("PMD") // I want to have the same method names as variable names on purpose
28 | public final class InternetObservingSettings {
29 | private final int initialInterval;
30 | private final int interval;
31 | private final String host;
32 | private final int port;
33 | private final int timeout;
34 | private final int httpResponse;
35 | private final ErrorHandler errorHandler;
36 | private final InternetObservingStrategy strategy;
37 |
38 | private InternetObservingSettings(int initialInterval, int interval, String host, int port,
39 | int timeout, int httpResponse, ErrorHandler errorHandler,
40 | InternetObservingStrategy strategy) {
41 | this.initialInterval = initialInterval;
42 | this.interval = interval;
43 | this.host = host;
44 | this.port = port;
45 | this.timeout = timeout;
46 | this.httpResponse = httpResponse;
47 | this.errorHandler = errorHandler;
48 | this.strategy = strategy;
49 | }
50 |
51 | /**
52 | * @return settings with default parameters
53 | */
54 | public static InternetObservingSettings create() {
55 | return new Builder().build();
56 | }
57 |
58 | private InternetObservingSettings(Builder builder) {
59 | this(builder.initialInterval, builder.interval, builder.host, builder.port, builder.timeout,
60 | builder.httpResponse, builder.errorHandler, builder.strategy);
61 | }
62 |
63 | private InternetObservingSettings() {
64 | this(builder());
65 | }
66 |
67 | /**
68 | * Creates builder object
69 | * @return Builder
70 | */
71 | public static Builder builder() {
72 | return new Builder();
73 | }
74 |
75 | /**
76 | * @return initial ping interval in milliseconds
77 | */
78 | public int initialInterval() {
79 | return initialInterval;
80 | }
81 |
82 | /**
83 | * @return ping interval in milliseconds
84 | */
85 | public int interval() {
86 | return interval;
87 | }
88 |
89 | /**
90 | * @return ping host
91 | */
92 | public String host() {
93 | return host;
94 | }
95 |
96 | /**
97 | * @return ping port
98 | */
99 | public int port() {
100 | return port;
101 | }
102 |
103 | /**
104 | * @return ping timeout in milliseconds
105 | */
106 | public int timeout() {
107 | return timeout;
108 | }
109 |
110 | public int httpResponse() {
111 | return httpResponse;
112 | }
113 |
114 | /**
115 | * @return error handler for pings and connections
116 | */
117 | public ErrorHandler errorHandler() {
118 | return errorHandler;
119 | }
120 |
121 | /**
122 | * @return internet observing strategy
123 | */
124 | public InternetObservingStrategy strategy() {
125 | return strategy;
126 | }
127 |
128 | /**
129 | * Settings builder, which contains default parameters
130 | */
131 | public final static class Builder {
132 | private int initialInterval = 0;
133 | private int interval = 2000;
134 | private String host = "http://clients3.google.com/generate_204";
135 | private int port = 80;
136 | private int timeout = 2000;
137 | private int httpResponse = HttpURLConnection.HTTP_NO_CONTENT;
138 | private ErrorHandler errorHandler = new DefaultErrorHandler();
139 | private InternetObservingStrategy strategy = new WalledGardenInternetObservingStrategy();
140 |
141 | private Builder() {
142 | }
143 |
144 | /**
145 | * sets initial ping interval in milliseconds
146 | *
147 | * @param initialInterval in milliseconds
148 | * @return Builder
149 | */
150 | public Builder initialInterval(int initialInterval) {
151 | this.initialInterval = initialInterval;
152 | return this;
153 | }
154 |
155 | /**
156 | * sets ping interval in milliseconds
157 | *
158 | * @param interval in milliseconds
159 | * @return Builder
160 | */
161 | public Builder interval(int interval) {
162 | this.interval = interval;
163 | return this;
164 | }
165 |
166 | /**
167 | * sets ping host
168 | *
169 | * @return Builder
170 | */
171 | public Builder host(String host) {
172 | this.host = host;
173 | return this;
174 | }
175 |
176 | /**
177 | * sets ping port
178 | *
179 | * @return Builder
180 | */
181 | public Builder port(int port) {
182 | this.port = port;
183 | return this;
184 | }
185 |
186 | /**
187 | * sets ping timeout in milliseconds
188 | *
189 | * @param timeout in milliseconds
190 | * @return Builder
191 | */
192 | public Builder timeout(int timeout) {
193 | this.timeout = timeout;
194 | return this;
195 | }
196 |
197 | /**
198 | * sets HTTP response code indicating that connection is established
199 | *
200 | * @param httpResponse as integer
201 | * @return Builder
202 | */
203 | public Builder httpResponse(final int httpResponse) {
204 | this.httpResponse = httpResponse;
205 | return this;
206 | }
207 |
208 | /**
209 | * sets error handler for pings and connections
210 | *
211 | * @return Builder
212 | */
213 | public Builder errorHandler(ErrorHandler errorHandler) {
214 | this.errorHandler = errorHandler;
215 | return this;
216 | }
217 |
218 | /**
219 | * sets internet observing strategy
220 | *
221 | * @param strategy for observing and internet connection
222 | * @return Builder
223 | */
224 | public Builder strategy(InternetObservingStrategy strategy) {
225 | this.strategy = strategy;
226 | return this;
227 | }
228 |
229 | public InternetObservingSettings build() {
230 | return new InternetObservingSettings(this);
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/InternetObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing;
17 |
18 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
19 | import io.reactivex.Observable;
20 | import io.reactivex.Single;
21 |
22 | /**
23 | * Internet observing strategy allows to implement different strategies for monitoring connectivity
24 | * with the Internet.
25 | */
26 | public interface InternetObservingStrategy {
27 | /**
28 | * Observes connectivity with the Internet by opening socket connection with remote host in a
29 | * given interval infinitely
30 | *
31 | * @param initialIntervalInMs in milliseconds determining the delay of the first connectivity
32 | * check
33 | * @param intervalInMs in milliseconds determining how often we want to check connectivity
34 | * @param host for checking Internet connectivity
35 | * @param port for checking Internet connectivity
36 | * @param timeoutInMs for pinging remote host in milliseconds
37 | * @param errorHandler for handling errors while checking connectivity
38 | * @return RxJava Observable with Boolean - true, when we have connection with host and false if
39 | * not
40 | */
41 | Observable observeInternetConnectivity(final int initialIntervalInMs,
42 | final int intervalInMs, final String host, final int port, final int timeoutInMs,
43 | final int httpResponse, final ErrorHandler errorHandler);
44 |
45 | /**
46 | * Observes connectivity with the Internet by opening socket connection with remote host once
47 | *
48 | * @param host for checking Internet connectivity
49 | * @param port for checking Internet connectivity
50 | * @param timeoutInMs for pinging remote host in milliseconds
51 | * @param errorHandler for handling errors while checking connectivity
52 | * @return RxJava Single with Boolean - true, when we have connection with host and false if
53 | * not
54 | */
55 | Single checkInternetConnectivity(final String host, final int port,
56 | final int timeoutInMs, final int httpResponse, final ErrorHandler errorHandler);
57 |
58 | /**
59 | * Gets default remote ping host for a given Internet Observing Strategy
60 | *
61 | * @return String with a ping host used in the current strategy
62 | */
63 | String getDefaultPingHost();
64 | }
65 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/error/DefaultErrorHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error;
17 |
18 | import android.util.Log;
19 | import com.jakewharton.nopen.annotation.Open;
20 |
21 | import static com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork.LOG_TAG;
22 |
23 | @Open public class DefaultErrorHandler implements ErrorHandler {
24 | @Override public void handleError(final Exception exception, final String message) {
25 | Log.e(LOG_TAG, message, exception);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/error/ErrorHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error;
17 |
18 | public interface ErrorHandler {
19 | void handleError(final Exception exception, final String message);
20 | }
21 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/strategy/SocketInternetObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy;
17 |
18 | import com.github.pwittchen.reactivenetwork.library.rx2.Preconditions;
19 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy;
20 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
21 | import com.jakewharton.nopen.annotation.Open;
22 | import io.reactivex.Observable;
23 | import io.reactivex.Single;
24 | import io.reactivex.SingleEmitter;
25 | import io.reactivex.SingleOnSubscribe;
26 | import io.reactivex.annotations.NonNull;
27 | import io.reactivex.functions.Function;
28 | import io.reactivex.schedulers.Schedulers;
29 | import java.io.IOException;
30 | import java.net.InetSocketAddress;
31 | import java.net.Socket;
32 | import java.util.concurrent.TimeUnit;
33 |
34 | /**
35 | * Socket strategy for monitoring connectivity with the Internet.
36 | * It monitors Internet connectivity via opening socket connection with the remote host.
37 | */
38 | @Open public class SocketInternetObservingStrategy implements InternetObservingStrategy {
39 | private static final String EMPTY_STRING = "";
40 | private static final String DEFAULT_HOST = "www.google.com";
41 | private static final String HTTP_PROTOCOL = "http://";
42 | private static final String HTTPS_PROTOCOL = "https://";
43 |
44 | @Override public String getDefaultPingHost() {
45 | return DEFAULT_HOST;
46 | }
47 |
48 | @Override public Observable observeInternetConnectivity(final int initialIntervalInMs,
49 | final int intervalInMs, final String host, final int port, final int timeoutInMs,
50 | final int httpResponse, final ErrorHandler errorHandler) {
51 | Preconditions.checkGreaterOrEqualToZero(initialIntervalInMs,
52 | "initialIntervalInMs is not a positive number");
53 | Preconditions.checkGreaterThanZero(intervalInMs, "intervalInMs is not a positive number");
54 | checkGeneralPreconditions(host, port, timeoutInMs, errorHandler);
55 |
56 | final String adjustedHost = adjustHost(host);
57 |
58 | return Observable.interval(initialIntervalInMs, intervalInMs, TimeUnit.MILLISECONDS,
59 | Schedulers.io()).map(new Function() {
60 | @Override public Boolean apply(@NonNull Long tick) throws Exception {
61 | return isConnected(adjustedHost, port, timeoutInMs, errorHandler);
62 | }
63 | }).distinctUntilChanged();
64 | }
65 |
66 | @Override public Single checkInternetConnectivity(final String host, final int port,
67 | final int timeoutInMs, final int httpResponse, final ErrorHandler errorHandler) {
68 | checkGeneralPreconditions(host, port, timeoutInMs, errorHandler);
69 |
70 | return Single.create(new SingleOnSubscribe() {
71 | @Override public void subscribe(@NonNull SingleEmitter emitter) throws Exception {
72 | emitter.onSuccess(isConnected(host, port, timeoutInMs, errorHandler));
73 | }
74 | });
75 | }
76 |
77 | /**
78 | * adjusts host to needs of SocketInternetObservingStrategy
79 | *
80 | * @return transformed host
81 | */
82 | protected String adjustHost(final String host) {
83 | if (host.startsWith(HTTP_PROTOCOL)) {
84 | return host.replace(HTTP_PROTOCOL, EMPTY_STRING);
85 | } else if (host.startsWith(HTTPS_PROTOCOL)) {
86 | return host.replace(HTTPS_PROTOCOL, EMPTY_STRING);
87 | }
88 | return host;
89 | }
90 |
91 | private void checkGeneralPreconditions(String host, int port, int timeoutInMs,
92 | ErrorHandler errorHandler) {
93 | Preconditions.checkNotNullOrEmpty(host, "host is null or empty");
94 | Preconditions.checkGreaterThanZero(port, "port is not a positive number");
95 | Preconditions.checkGreaterThanZero(timeoutInMs, "timeoutInMs is not a positive number");
96 | Preconditions.checkNotNull(errorHandler, "errorHandler is null");
97 | }
98 |
99 | /**
100 | * checks if device is connected to given host at given port
101 | *
102 | * @param host to connect
103 | * @param port to connect
104 | * @param timeoutInMs connection timeout
105 | * @param errorHandler error handler for socket connection
106 | * @return boolean true if connected and false if not
107 | */
108 | protected boolean isConnected(final String host, final int port, final int timeoutInMs,
109 | final ErrorHandler errorHandler) {
110 | final Socket socket = new Socket();
111 | return isConnected(socket, host, port, timeoutInMs, errorHandler);
112 | }
113 |
114 | /**
115 | * checks if device is connected to given host at given port
116 | *
117 | * @param socket to connect
118 | * @param host to connect
119 | * @param port to connect
120 | * @param timeoutInMs connection timeout
121 | * @param errorHandler error handler for socket connection
122 | * @return boolean true if connected and false if not
123 | */
124 | protected boolean isConnected(final Socket socket, final String host, final int port,
125 | final int timeoutInMs, final ErrorHandler errorHandler) {
126 | boolean isConnected;
127 | try {
128 | socket.connect(new InetSocketAddress(host, port), timeoutInMs);
129 | isConnected = socket.isConnected();
130 | } catch (IOException e) {
131 | isConnected = Boolean.FALSE;
132 | } finally {
133 | try {
134 | socket.close();
135 | } catch (IOException exception) {
136 | errorHandler.handleError(exception, "Could not close the socket");
137 | }
138 | }
139 | return isConnected;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/strategy/WalledGardenInternetObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy;
17 |
18 | import com.github.pwittchen.reactivenetwork.library.rx2.Preconditions;
19 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy;
20 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
21 | import com.jakewharton.nopen.annotation.Open;
22 | import io.reactivex.Observable;
23 | import io.reactivex.Single;
24 | import io.reactivex.SingleEmitter;
25 | import io.reactivex.SingleOnSubscribe;
26 | import io.reactivex.annotations.NonNull;
27 | import io.reactivex.functions.Function;
28 | import io.reactivex.schedulers.Schedulers;
29 | import java.io.IOException;
30 | import java.net.HttpURLConnection;
31 | import java.net.URL;
32 | import java.util.concurrent.TimeUnit;
33 | import javax.net.ssl.HttpsURLConnection;
34 |
35 | /**
36 | * Walled Garden Strategy for monitoring connectivity with the Internet.
37 | * This strategy handle use case of the countries behind Great Firewall (e.g. China),
38 | * which does not has access to several websites like Google. It such case, different HTTP responses
39 | * are generated. Instead HTTP 200 (OK), we got HTTP 204 (NO CONTENT), but it still can tell us
40 | * if a device is connected to the Internet or not.
41 | */
42 | @Open public class WalledGardenInternetObservingStrategy implements InternetObservingStrategy {
43 | private static final String DEFAULT_HOST = "http://clients3.google.com/generate_204";
44 | private static final String HTTP_PROTOCOL = "http://";
45 | private static final String HTTPS_PROTOCOL = "https://";
46 |
47 | @Override public String getDefaultPingHost() {
48 | return DEFAULT_HOST;
49 | }
50 |
51 | @Override public Observable observeInternetConnectivity(final int initialIntervalInMs,
52 | final int intervalInMs, final String host, final int port, final int timeoutInMs,
53 | final int httpResponse,
54 | final ErrorHandler errorHandler) {
55 |
56 | Preconditions.checkGreaterOrEqualToZero(initialIntervalInMs,
57 | "initialIntervalInMs is not a positive number");
58 | Preconditions.checkGreaterThanZero(intervalInMs, "intervalInMs is not a positive number");
59 | checkGeneralPreconditions(host, port, timeoutInMs, httpResponse, errorHandler);
60 |
61 | final String adjustedHost = adjustHost(host);
62 |
63 | return Observable.interval(initialIntervalInMs, intervalInMs, TimeUnit.MILLISECONDS,
64 | Schedulers.io()).map(new Function() {
65 | @Override public Boolean apply(@NonNull Long tick) {
66 | return isConnected(adjustedHost, port, timeoutInMs, httpResponse, errorHandler);
67 | }
68 | }).distinctUntilChanged();
69 | }
70 |
71 | @Override public Single checkInternetConnectivity(final String host, final int port,
72 | final int timeoutInMs, final int httpResponse, final ErrorHandler errorHandler) {
73 | checkGeneralPreconditions(host, port, timeoutInMs, httpResponse, errorHandler);
74 |
75 | return Single.create(new SingleOnSubscribe() {
76 | @Override public void subscribe(@NonNull SingleEmitter emitter) {
77 | emitter.onSuccess(isConnected(host, port, timeoutInMs, httpResponse, errorHandler));
78 | }
79 | });
80 | }
81 |
82 | protected String adjustHost(final String host) {
83 | if (!host.startsWith(HTTP_PROTOCOL) && !host.startsWith(HTTPS_PROTOCOL)) {
84 | return HTTPS_PROTOCOL.concat(host);
85 | }
86 |
87 | return host;
88 | }
89 |
90 | private void checkGeneralPreconditions(final String host, final int port, final int timeoutInMs,
91 | final int httpResponse, final ErrorHandler errorHandler) {
92 | Preconditions.checkNotNullOrEmpty(host, "host is null or empty");
93 | Preconditions.checkGreaterThanZero(port, "port is not a positive number");
94 | Preconditions.checkGreaterThanZero(timeoutInMs, "timeoutInMs is not a positive number");
95 | Preconditions.checkNotNull(errorHandler, "errorHandler is null");
96 | Preconditions.checkNotNull(httpResponse, "httpResponse is null");
97 | Preconditions.checkGreaterThanZero(httpResponse, "httpResponse is not a positive number");
98 | }
99 |
100 | protected Boolean isConnected(final String host, final int port, final int timeoutInMs,
101 | final int httpResponse, final ErrorHandler errorHandler) {
102 | HttpURLConnection urlConnection = null;
103 | try {
104 | if (host.startsWith(HTTPS_PROTOCOL)) {
105 | urlConnection = createHttpsUrlConnection(host, port, timeoutInMs);
106 | } else {
107 | urlConnection = createHttpUrlConnection(host, port, timeoutInMs);
108 | }
109 | return urlConnection.getResponseCode() == httpResponse;
110 | } catch (IOException e) {
111 | errorHandler.handleError(e, "Could not establish connection with WalledGardenStrategy");
112 | return Boolean.FALSE;
113 | } finally {
114 | if (urlConnection != null) {
115 | urlConnection.disconnect();
116 | }
117 | }
118 | }
119 |
120 | protected HttpURLConnection createHttpUrlConnection(final String host, final int port,
121 | final int timeoutInMs) throws IOException {
122 | URL initialUrl = new URL(host);
123 | URL url = new URL(initialUrl.getProtocol(), initialUrl.getHost(), port, initialUrl.getFile());
124 | HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
125 | urlConnection.setConnectTimeout(timeoutInMs);
126 | urlConnection.setReadTimeout(timeoutInMs);
127 | urlConnection.setInstanceFollowRedirects(false);
128 | urlConnection.setUseCaches(false);
129 | return urlConnection;
130 | }
131 |
132 | protected HttpsURLConnection createHttpsUrlConnection(final String host, final int port,
133 | final int timeoutInMs) throws IOException {
134 | URL initialUrl = new URL(host);
135 | URL url = new URL(initialUrl.getProtocol(), initialUrl.getHost(), port, initialUrl.getFile());
136 | HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
137 | urlConnection.setConnectTimeout(timeoutInMs);
138 | urlConnection.setReadTimeout(timeoutInMs);
139 | urlConnection.setInstanceFollowRedirects(false);
140 | urlConnection.setUseCaches(false);
141 | return urlConnection;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/NetworkObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing;
17 |
18 | import android.content.Context;
19 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
20 | import io.reactivex.Observable;
21 |
22 | /**
23 | * Network observing strategy allows to implement different strategies for monitoring network
24 | * connectivity change. Network monitoring API may differ depending of specific Android version.
25 | */
26 | public interface NetworkObservingStrategy {
27 | /**
28 | * Observes network connectivity
29 | *
30 | * @param context of the Activity or an Application
31 | * @return Observable representing stream of the network connectivity
32 | */
33 | Observable observeNetworkConnectivity(final Context context);
34 |
35 | /**
36 | * Handles errors, which occurred during observing network connectivity
37 | *
38 | * @param message to be processed
39 | * @param exception which was thrown
40 | */
41 | void onError(final String message, final Exception exception);
42 | }
43 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/strategy/LollipopNetworkObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.net.ConnectivityManager;
21 | import android.net.ConnectivityManager.NetworkCallback;
22 | import android.net.Network;
23 | import android.net.NetworkRequest;
24 | import android.util.Log;
25 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
26 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
27 | import com.jakewharton.nopen.annotation.Open;
28 | import io.reactivex.Observable;
29 | import io.reactivex.ObservableEmitter;
30 | import io.reactivex.ObservableOnSubscribe;
31 | import io.reactivex.functions.Action;
32 |
33 | import static com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork.LOG_TAG;
34 |
35 | /**
36 | * Network observing strategy for devices with Android Lollipop (API 21) or higher.
37 | * Uses Network Callback API.
38 | */
39 | @Open @TargetApi(21) public class LollipopNetworkObservingStrategy
40 | implements NetworkObservingStrategy {
41 | @SuppressWarnings("NullAway") // it has to be initialized in the Observable due to Context
42 | private NetworkCallback networkCallback;
43 |
44 | @Override public Observable observeNetworkConnectivity(final Context context) {
45 | final String service = Context.CONNECTIVITY_SERVICE;
46 | final ConnectivityManager manager = (ConnectivityManager) context.getSystemService(service);
47 |
48 | return Observable.create(new ObservableOnSubscribe() {
49 | @Override public void subscribe(ObservableEmitter subscriber) throws Exception {
50 | networkCallback = createNetworkCallback(subscriber, context);
51 | final NetworkRequest networkRequest = new NetworkRequest.Builder().build();
52 | manager.registerNetworkCallback(networkRequest, networkCallback);
53 | }
54 | }).doOnDispose(new Action() {
55 | @Override public void run() {
56 | tryToUnregisterCallback(manager);
57 | }
58 | }).startWith(Connectivity.create(context)).distinctUntilChanged();
59 | }
60 |
61 | private void tryToUnregisterCallback(final ConnectivityManager manager) {
62 | try {
63 | manager.unregisterNetworkCallback(networkCallback);
64 | } catch (Exception exception) {
65 | onError("could not unregister network callback", exception);
66 | }
67 | }
68 |
69 | @Override public void onError(final String message, final Exception exception) {
70 | Log.e(LOG_TAG, message, exception);
71 | }
72 |
73 | private NetworkCallback createNetworkCallback(final ObservableEmitter subscriber,
74 | final Context context) {
75 | return new ConnectivityManager.NetworkCallback() {
76 | @Override public void onAvailable(Network network) {
77 | subscriber.onNext(Connectivity.create(context));
78 | }
79 |
80 | @Override public void onLost(Network network) {
81 | subscriber.onNext(Connectivity.create(context));
82 | }
83 | };
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/strategy/MarshmallowNetworkObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.BroadcastReceiver;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.content.IntentFilter;
23 | import android.net.ConnectivityManager;
24 | import android.net.Network;
25 | import android.net.NetworkCapabilities;
26 | import android.net.NetworkInfo;
27 | import android.net.NetworkRequest;
28 | import android.os.PowerManager;
29 | import android.util.Log;
30 | import androidx.annotation.NonNull;
31 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
32 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
33 | import com.jakewharton.nopen.annotation.Open;
34 | import io.reactivex.BackpressureStrategy;
35 | import io.reactivex.Flowable;
36 | import io.reactivex.Observable;
37 | import io.reactivex.functions.Action;
38 | import io.reactivex.functions.Consumer;
39 | import io.reactivex.functions.Function;
40 | import io.reactivex.subjects.PublishSubject;
41 | import io.reactivex.subjects.Subject;
42 | import org.reactivestreams.Publisher;
43 |
44 | import static com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork.LOG_TAG;
45 |
46 | /**
47 | * Network observing strategy for devices with Android Marshmallow (API 23) or higher.
48 | * Uses Network Callback API and handles Doze mode.
49 | */
50 | @Open @TargetApi(23) public class MarshmallowNetworkObservingStrategy
51 | implements NetworkObservingStrategy {
52 | protected static final String ERROR_MSG_NETWORK_CALLBACK =
53 | "could not unregister network callback";
54 | protected static final String ERROR_MSG_RECEIVER = "could not unregister receiver";
55 |
56 | @SuppressWarnings("NullAway") // it has to be initialized in the Observable due to Context
57 | private ConnectivityManager.NetworkCallback networkCallback;
58 | private final Subject connectivitySubject;
59 | private final BroadcastReceiver idleReceiver;
60 | private Connectivity lastConnectivity = Connectivity.create();
61 |
62 | @SuppressWarnings("NullAway") // networkCallback cannot be initialized here
63 | public MarshmallowNetworkObservingStrategy() {
64 | this.idleReceiver = createIdleBroadcastReceiver();
65 | this.connectivitySubject = PublishSubject.create().toSerialized();
66 | }
67 |
68 | @Override public Observable observeNetworkConnectivity(final Context context) {
69 | final String service = Context.CONNECTIVITY_SERVICE;
70 | final ConnectivityManager manager = (ConnectivityManager) context.getSystemService(service);
71 | networkCallback = createNetworkCallback(context);
72 |
73 | registerIdleReceiver(context);
74 |
75 | final NetworkRequest request =
76 | new NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
77 | .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
78 | .build();
79 |
80 | manager.registerNetworkCallback(request, networkCallback);
81 |
82 | return connectivitySubject.toFlowable(BackpressureStrategy.LATEST).doOnCancel(new Action() {
83 | @Override public void run() {
84 | tryToUnregisterCallback(manager);
85 | tryToUnregisterReceiver(context);
86 | }
87 | }).doAfterNext(new Consumer() {
88 | @Override
89 | public void accept(final Connectivity connectivity) {
90 | lastConnectivity = connectivity;
91 | }
92 | }).flatMap(new Function>() {
93 | @Override
94 | public Publisher apply(final Connectivity connectivity) {
95 | return propagateAnyConnectedState(lastConnectivity, connectivity);
96 | }
97 | }).startWith(Connectivity.create(context)).distinctUntilChanged().toObservable();
98 | }
99 |
100 | protected Publisher propagateAnyConnectedState(final Connectivity last,
101 | final Connectivity current) {
102 | final boolean typeChanged = last.type() != current.type();
103 | final boolean wasConnected = last.state() == NetworkInfo.State.CONNECTED;
104 | final boolean isDisconnected = current.state() == NetworkInfo.State.DISCONNECTED;
105 | final boolean isNotIdle = current.detailedState() != NetworkInfo.DetailedState.IDLE;
106 |
107 | if (typeChanged && wasConnected && isDisconnected && isNotIdle) {
108 | return Flowable.fromArray(current, last);
109 | } else {
110 | return Flowable.fromArray(current);
111 | }
112 | }
113 |
114 | protected void registerIdleReceiver(final Context context) {
115 | final IntentFilter filter = new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
116 | context.registerReceiver(idleReceiver, filter);
117 | }
118 |
119 | @NonNull protected BroadcastReceiver createIdleBroadcastReceiver() {
120 | return new BroadcastReceiver() {
121 | @Override public void onReceive(final Context context, final Intent intent) {
122 | if (isIdleMode(context)) {
123 | onNext(Connectivity.create());
124 | } else {
125 | onNext(Connectivity.create(context));
126 | }
127 | }
128 | };
129 | }
130 |
131 | protected boolean isIdleMode(final Context context) {
132 | final String packageName = context.getPackageName();
133 | final PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
134 | boolean isIgnoringOptimizations = manager.isIgnoringBatteryOptimizations(packageName);
135 | return manager.isDeviceIdleMode() && !isIgnoringOptimizations;
136 | }
137 |
138 | protected void tryToUnregisterCallback(final ConnectivityManager manager) {
139 | try {
140 | manager.unregisterNetworkCallback(networkCallback);
141 | } catch (Exception exception) {
142 | onError(ERROR_MSG_NETWORK_CALLBACK, exception);
143 | }
144 | }
145 |
146 | protected void tryToUnregisterReceiver(Context context) {
147 | try {
148 | context.unregisterReceiver(idleReceiver);
149 | } catch (Exception exception) {
150 | onError(ERROR_MSG_RECEIVER, exception);
151 | }
152 | }
153 |
154 | @Override public void onError(final String message, final Exception exception) {
155 | Log.e(LOG_TAG, message, exception);
156 | }
157 |
158 | protected ConnectivityManager.NetworkCallback createNetworkCallback(final Context context) {
159 | return new ConnectivityManager.NetworkCallback() {
160 | @Override public void onAvailable(Network network) {
161 | onNext(Connectivity.create(context));
162 | }
163 |
164 | @Override public void onLost(Network network) {
165 | onNext(Connectivity.create(context));
166 | }
167 | };
168 | }
169 |
170 | protected void onNext(Connectivity connectivity) {
171 | connectivitySubject.onNext(connectivity);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/strategy/PreLollipopNetworkObservingStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy;
17 |
18 | import android.content.BroadcastReceiver;
19 | import android.content.Context;
20 | import android.content.Intent;
21 | import android.content.IntentFilter;
22 | import android.net.ConnectivityManager;
23 | import android.os.Looper;
24 | import android.util.Log;
25 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
26 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
27 | import com.jakewharton.nopen.annotation.Open;
28 | import io.reactivex.Observable;
29 | import io.reactivex.ObservableEmitter;
30 | import io.reactivex.ObservableOnSubscribe;
31 | import io.reactivex.Scheduler;
32 | import io.reactivex.android.schedulers.AndroidSchedulers;
33 | import io.reactivex.disposables.Disposable;
34 | import io.reactivex.disposables.Disposables;
35 | import io.reactivex.functions.Action;
36 |
37 | import static com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork.LOG_TAG;
38 |
39 | /**
40 | * Network observing strategy for Android devices before Lollipop (API 20 or lower).
41 | * Uses Broadcast Receiver.
42 | */
43 | @Open public class PreLollipopNetworkObservingStrategy implements NetworkObservingStrategy {
44 |
45 | @Override public Observable observeNetworkConnectivity(final Context context) {
46 | final IntentFilter filter = new IntentFilter();
47 | filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
48 |
49 | return Observable.create(new ObservableOnSubscribe() {
50 | @Override public void subscribe(final ObservableEmitter emitter)
51 | throws Exception {
52 | final BroadcastReceiver receiver = new BroadcastReceiver() {
53 | @Override public void onReceive(Context context, Intent intent) {
54 | emitter.onNext(Connectivity.create(context));
55 | }
56 | };
57 |
58 | context.registerReceiver(receiver, filter);
59 |
60 | Disposable disposable = disposeInUiThread(new Action() {
61 | @Override public void run() {
62 | tryToUnregisterReceiver(context, receiver);
63 | }
64 | });
65 | emitter.setDisposable(disposable);
66 | }
67 | }).defaultIfEmpty(Connectivity.create());
68 | }
69 |
70 | protected void tryToUnregisterReceiver(final Context context, final BroadcastReceiver receiver) {
71 | try {
72 | context.unregisterReceiver(receiver);
73 | } catch (Exception exception) {
74 | onError("receiver was already unregistered", exception);
75 | }
76 | }
77 |
78 | @Override public void onError(final String message, final Exception exception) {
79 | Log.e(LOG_TAG, message, exception);
80 | }
81 |
82 | private Disposable disposeInUiThread(final Action action) {
83 | return Disposables.fromAction(new Action() {
84 | @Override public void run() throws Exception {
85 | if (Looper.getMainLooper() == Looper.myLooper()) {
86 | action.run();
87 | } else {
88 | final Scheduler.Worker inner = AndroidSchedulers.mainThread().createWorker();
89 | inner.schedule(new Runnable() {
90 | @Override public void run() {
91 | try {
92 | action.run();
93 | } catch (Exception e) {
94 | onError("Could not unregister receiver in UI Thread", e);
95 | }
96 | inner.dispose();
97 | }
98 | });
99 | }
100 | }
101 | });
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/ConnectivityTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import android.content.Context;
19 | import android.net.ConnectivityManager;
20 | import android.net.NetworkInfo;
21 | import io.reactivex.functions.Predicate;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 | import org.robolectric.RobolectricTestRunner;
25 | import org.robolectric.RuntimeEnvironment;
26 |
27 | import static com.google.common.truth.Truth.assertThat;
28 |
29 | @RunWith(RobolectricTestRunner.class)
30 | @SuppressWarnings("NullAway") public class ConnectivityTest {
31 | private static final String TYPE_NAME_WIFI = "WIFI";
32 | private static final String TYPE_NAME_MOBILE = "MOBILE";
33 | private static final String TYPE_NAME_NONE = "NONE";
34 |
35 | @Test public void shouldCreateConnectivity() {
36 | // when
37 | Connectivity connectivity = Connectivity.create();
38 |
39 | // then
40 | assertThat(connectivity).isNotNull();
41 | assertThat(connectivity.state()).isEqualTo(NetworkInfo.State.DISCONNECTED);
42 | assertThat(connectivity.detailedState()).isEqualTo(NetworkInfo.DetailedState.IDLE);
43 | assertThat(connectivity.type()).isEqualTo(Connectivity.UNKNOWN_TYPE);
44 | assertThat(connectivity.subType()).isEqualTo(Connectivity.UNKNOWN_SUB_TYPE);
45 | assertThat(connectivity.available()).isFalse();
46 | assertThat(connectivity.failover()).isFalse();
47 | assertThat(connectivity.roaming()).isFalse();
48 | assertThat(connectivity.typeName()).isEqualTo(TYPE_NAME_NONE);
49 | assertThat(connectivity.subTypeName()).isEqualTo(TYPE_NAME_NONE);
50 | assertThat(connectivity.reason()).isEmpty();
51 | assertThat(connectivity.extraInfo()).isEmpty();
52 | }
53 |
54 | @Test public void stateShouldBeEqualToGivenValue() throws Exception {
55 | // given
56 | final Connectivity connectivity = Connectivity.state(NetworkInfo.State.CONNECTED)
57 | .type(ConnectivityManager.TYPE_WIFI)
58 | .typeName(TYPE_NAME_WIFI)
59 | .build();
60 |
61 | // when
62 | final Predicate equalTo = ConnectivityPredicate.hasState(connectivity.state());
63 | final Boolean shouldBeEqualToGivenStatus = equalTo.test(connectivity);
64 |
65 | // then
66 | assertThat(shouldBeEqualToGivenStatus).isTrue();
67 | }
68 |
69 | @Test public void stateShouldBeEqualToOneOfGivenMultipleValues() throws Exception {
70 | // given
71 | final Connectivity connectivity = Connectivity.state(NetworkInfo.State.CONNECTING)
72 | .type(ConnectivityManager.TYPE_WIFI)
73 | .typeName(TYPE_NAME_WIFI)
74 | .build();
75 |
76 | //noinspection CStyleArrayDeclaration
77 | final NetworkInfo.State states[] =
78 | { NetworkInfo.State.CONNECTED, NetworkInfo.State.CONNECTING };
79 |
80 | // when
81 | final Predicate equalTo = ConnectivityPredicate.hasState(states);
82 | final Boolean shouldBeEqualToGivenStatus = equalTo.test(connectivity);
83 |
84 | // then
85 | assertThat(shouldBeEqualToGivenStatus).isTrue();
86 | }
87 |
88 | @Test public void stateShouldNotBeEqualToGivenValue() throws Exception {
89 | // given
90 | final Connectivity connectivity =
91 | Connectivity.state(NetworkInfo.State.DISCONNECTED)
92 | .type(ConnectivityManager.TYPE_WIFI)
93 | .typeName(TYPE_NAME_WIFI)
94 | .build();
95 |
96 | // when
97 | final Predicate equalTo =
98 | ConnectivityPredicate.hasState(NetworkInfo.State.CONNECTED);
99 | final Boolean shouldBeEqualToGivenStatus = equalTo.test(connectivity);
100 |
101 | // then
102 | assertThat(shouldBeEqualToGivenStatus).isFalse();
103 | }
104 |
105 | @Test public void typeShouldBeEqualToGivenValue() throws Exception {
106 | // given
107 | final Connectivity connectivity = Connectivity.state(NetworkInfo.State.CONNECTED)
108 | .type(ConnectivityManager.TYPE_WIFI)
109 | .typeName(TYPE_NAME_WIFI)
110 | .build();
111 |
112 | // note that unknown type is added initially by the ConnectivityPredicate#hasType method
113 | //noinspection CStyleArrayDeclaration
114 | final int givenTypes[] = { connectivity.type(), Connectivity.UNKNOWN_TYPE };
115 |
116 | // when
117 | final Predicate equalTo = ConnectivityPredicate.hasType(givenTypes);
118 | final Boolean shouldBeEqualToGivenStatus = equalTo.test(connectivity);
119 |
120 | // then
121 | assertThat(shouldBeEqualToGivenStatus).isTrue();
122 | }
123 |
124 | @Test public void typeShouldBeEqualToOneOfGivenMultipleValues() throws Exception {
125 | // given
126 | final Connectivity connectivity = Connectivity.state(NetworkInfo.State.CONNECTING)
127 | .type(ConnectivityManager.TYPE_MOBILE)
128 | .typeName(TYPE_NAME_MOBILE)
129 | .build();
130 |
131 | // note that unknown type is added initially by the ConnectivityPredicate#hasType method
132 | //noinspection CStyleArrayDeclaration
133 | final int givenTypes[] = {
134 | ConnectivityManager.TYPE_WIFI, ConnectivityManager.TYPE_MOBILE, Connectivity.UNKNOWN_TYPE
135 | };
136 |
137 | // when
138 | final Predicate equalTo = ConnectivityPredicate.hasType(givenTypes);
139 | final Boolean shouldBeEqualToGivenStatus = equalTo.test(connectivity);
140 |
141 | // then
142 | assertThat(shouldBeEqualToGivenStatus).isTrue();
143 | }
144 |
145 | @Test public void typeShouldNotBeEqualToGivenValue() throws Exception {
146 | // given
147 | final Connectivity connectivity = Connectivity.state(NetworkInfo.State.CONNECTED)
148 | .type(ConnectivityManager.TYPE_WIFI)
149 | .typeName(TYPE_NAME_WIFI)
150 | .build();
151 |
152 | // note that unknown type is added initially by the ConnectivityPredicate#hasType method
153 | //noinspection CStyleArrayDeclaration
154 | final int givenTypes[] = { ConnectivityManager.TYPE_MOBILE, Connectivity.UNKNOWN_TYPE };
155 |
156 | // when
157 | final Predicate equalTo = ConnectivityPredicate.hasType(givenTypes);
158 | final Boolean shouldBeEqualToGivenStatus = equalTo.test(connectivity);
159 |
160 | // then
161 | assertThat(shouldBeEqualToGivenStatus).isFalse();
162 | }
163 |
164 | @Test(expected = IllegalArgumentException.class)
165 | public void createShouldThrowAnExceptionWhenContextIsNull() {
166 | // given
167 | final Context context = null;
168 |
169 | // when
170 | //noinspection ConstantConditions
171 | Connectivity.create(context);
172 |
173 | // then
174 | // an exception is thrown
175 | }
176 |
177 | @Test public void shouldReturnProperToStringValue() {
178 | // given
179 | final String expectedToString = "Connectivity{"
180 | + "state=DISCONNECTED, "
181 | + "detailedState=IDLE, "
182 | + "type=-1, "
183 | + "subType=-1, "
184 | + "available=false, "
185 | + "failover=false, "
186 | + "roaming=false, "
187 | + "typeName='NONE', "
188 | + "subTypeName='NONE', "
189 | + "reason='', "
190 | + "extraInfo=''}";
191 |
192 | // when
193 | Connectivity connectivity = Connectivity.create();
194 |
195 | // then
196 | assertThat(connectivity.toString()).isEqualTo(expectedToString);
197 | }
198 |
199 | @Test public void theSameConnectivityObjectsShouldBeEqual() {
200 | // given
201 | final Connectivity connectivityOne = Connectivity.create();
202 | final Connectivity connectivityTwo = Connectivity.create();
203 |
204 | // when
205 | boolean objectsAreEqual = connectivityOne.equals(connectivityTwo);
206 |
207 | // then
208 | assertThat(objectsAreEqual).isTrue();
209 | }
210 |
211 | @Test public void twoDefaultObjectsShouldBeInTheSameBucket() {
212 | // given
213 | final Connectivity connectivityOne = Connectivity.create();
214 | final Connectivity connectivityTwo = Connectivity.create();
215 |
216 | // when
217 | boolean hashCodesAreEqual = connectivityOne.hashCode() == connectivityTwo.hashCode();
218 |
219 | // then
220 | assertThat(hashCodesAreEqual).isTrue();
221 | }
222 |
223 | @Test public void shouldAppendUnknownTypeWhileFilteringNetworkTypesInsidePredicate() {
224 | // given
225 | int[] types = { ConnectivityManager.TYPE_MOBILE, ConnectivityManager.TYPE_WIFI };
226 | int[] expectedOutputTypes = {
227 | ConnectivityManager.TYPE_MOBILE, ConnectivityManager.TYPE_WIFI, Connectivity.UNKNOWN_TYPE
228 | };
229 |
230 | // when
231 | int[] outputTypes = ConnectivityPredicate.appendUnknownNetworkTypeToTypes(types);
232 |
233 | // then
234 | assertThat(outputTypes).isEqualTo(expectedOutputTypes);
235 | }
236 |
237 | @Test
238 | public void shouldAppendUnknownTypeWhileFilteringNetworkTypesInsidePredicateForEmptyArray() {
239 | // given
240 | int[] types = {};
241 | int[] expectedOutputTypes = { Connectivity.UNKNOWN_TYPE };
242 |
243 | // when
244 | int[] outputTypes = ConnectivityPredicate.appendUnknownNetworkTypeToTypes(types);
245 |
246 | // then
247 | assertThat(outputTypes).isEqualTo(expectedOutputTypes);
248 | }
249 |
250 | @Test public void shouldCreateConnectivityWithBuilder() {
251 | // given
252 | NetworkInfo.State state = NetworkInfo.State.CONNECTED;
253 | NetworkInfo.DetailedState detailedState = NetworkInfo.DetailedState.CONNECTED;
254 | int type = ConnectivityManager.TYPE_WIFI;
255 | int subType = ConnectivityManager.TYPE_WIMAX;
256 | String typeName = TYPE_NAME_WIFI;
257 | String subTypeName = "test subType";
258 | String reason = "no reason";
259 | String extraInfo = "extra info";
260 |
261 | // when
262 | Connectivity connectivity = Connectivity.state(state)
263 | .detailedState(detailedState)
264 | .type(type)
265 | .subType(subType)
266 | .available(true)
267 | .failover(false)
268 | .roaming(true)
269 | .typeName(typeName)
270 | .subTypeName(subTypeName)
271 | .reason(reason)
272 | .extraInfo(extraInfo)
273 | .build();
274 |
275 | // then
276 | assertThat(connectivity.state()).isEqualTo(state);
277 | assertThat(connectivity.detailedState()).isEqualTo(detailedState);
278 | assertThat(connectivity.type()).isEqualTo(type);
279 | assertThat(connectivity.subType()).isEqualTo(subType);
280 | assertThat(connectivity.available()).isTrue();
281 | assertThat(connectivity.failover()).isFalse();
282 | assertThat(connectivity.roaming()).isTrue();
283 | assertThat(connectivity.typeName()).isEqualTo(typeName);
284 | assertThat(connectivity.subTypeName()).isEqualTo(subTypeName);
285 | assertThat(connectivity.reason()).isEqualTo(reason);
286 | assertThat(connectivity.extraInfo()).isEqualTo(extraInfo);
287 | }
288 |
289 | @Test public void connectivityShouldNotBeEqualToAnotherOne() {
290 | // given
291 | Connectivity connectivityOne = Connectivity.state(NetworkInfo.State.CONNECTED)
292 | .detailedState(NetworkInfo.DetailedState.CONNECTED)
293 | .type(ConnectivityManager.TYPE_WIFI)
294 | .subType(1)
295 | .available(true)
296 | .failover(true)
297 | .roaming(true)
298 | .typeName(TYPE_NAME_WIFI)
299 | .subTypeName("subtypeOne")
300 | .reason("reasonOne")
301 | .extraInfo("extraInfoOne")
302 | .build();
303 |
304 | Connectivity connectivityTwo = Connectivity.state(NetworkInfo.State.DISCONNECTED)
305 | .detailedState(NetworkInfo.DetailedState.DISCONNECTED)
306 | .type(ConnectivityManager.TYPE_MOBILE)
307 | .subType(2)
308 | .available(false)
309 | .failover(false)
310 | .roaming(false)
311 | .typeName(TYPE_NAME_MOBILE)
312 | .subTypeName("subtypeTwo")
313 | .reason("reasonTwo")
314 | .extraInfo("extraInfoTwo")
315 | .build();
316 |
317 | // when
318 | final boolean isAnotherConnectivityTheSame = connectivityOne.equals(connectivityTwo);
319 |
320 | // then
321 | assertThat(isAnotherConnectivityTheSame).isFalse();
322 | }
323 |
324 | @Test public void shouldCreateDefaultConnectivityWhenConnectivityManagerIsNull() {
325 | // given
326 | final Context context = RuntimeEnvironment.getApplication().getApplicationContext();
327 | final ConnectivityManager connectivityManager = null;
328 |
329 | // when
330 | @SuppressWarnings("ConstantConditions")
331 | Connectivity connectivity = Connectivity.create(context, connectivityManager);
332 |
333 | // then
334 | assertThat(connectivity.type()).isEqualTo(Connectivity.UNKNOWN_TYPE);
335 | assertThat(connectivity.subType()).isEqualTo(Connectivity.UNKNOWN_SUB_TYPE);
336 | assertThat(connectivity.state()).isEqualTo(NetworkInfo.State.DISCONNECTED);
337 | assertThat(connectivity.detailedState()).isEqualTo(NetworkInfo.DetailedState.IDLE);
338 | assertThat(connectivity.available()).isFalse();
339 | assertThat(connectivity.failover()).isFalse();
340 | assertThat(connectivity.roaming()).isFalse();
341 | assertThat(connectivity.typeName()).isEqualTo(TYPE_NAME_NONE);
342 | assertThat(connectivity.subTypeName()).isEqualTo(TYPE_NAME_NONE);
343 | assertThat(connectivity.reason()).isEmpty();
344 | assertThat(connectivity.extraInfo()).isEmpty();
345 | }
346 | }
347 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/PreconditionsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import org.junit.Test;
19 | import org.junit.runner.RunWith;
20 | import org.robolectric.RobolectricTestRunner;
21 | import org.robolectric.annotation.Config;
22 |
23 | import static com.google.common.truth.Truth.assertThat;
24 |
25 | @RunWith(RobolectricTestRunner.class)
26 | @SuppressWarnings("NullAway") public class PreconditionsTest {
27 |
28 | private static final String MSG_STRING_IS_NULL = "String is null";
29 | private static final String MSG_VALUE_IS_NOT_GREATER_THAN_ZERO = "value is not greater than zero";
30 |
31 | @Test @Config(sdk = 21) public void shouldBeAtLeastAndroidLollipop() {
32 | boolean isAtLeastAndroidLollipop = Preconditions.isAtLeastAndroidLollipop();
33 | assertThat(isAtLeastAndroidLollipop).isTrue();
34 | }
35 |
36 | @Test @Config(sdk = 22) public void shouldBeAtLeastAndroidLollipopForHigherApi() {
37 | boolean isAtLeastAndroidLollipop = Preconditions.isAtLeastAndroidLollipop();
38 | assertThat(isAtLeastAndroidLollipop).isTrue();
39 | }
40 |
41 | @Test @Config(sdk = 22) public void shouldNotBeAtLeastAndroidMarshmallowForLowerApi() {
42 | boolean isAtLeastAndroidMarshmallow = Preconditions.isAtLeastAndroidMarshmallow();
43 | assertThat(isAtLeastAndroidMarshmallow).isFalse();
44 | }
45 |
46 | @Test @Config(sdk = 23) public void shouldBeAtLeastAndroidMarshmallow() {
47 | boolean isAtLeastAndroidMarshmallow = Preconditions.isAtLeastAndroidMarshmallow();
48 | assertThat(isAtLeastAndroidMarshmallow).isTrue();
49 | }
50 |
51 | @Test(expected = IllegalArgumentException.class)
52 | public void shouldThrowAnExceptionWhenStringIsNull() {
53 | Preconditions.checkNotNullOrEmpty(null, MSG_STRING_IS_NULL);
54 | }
55 |
56 | @Test(expected = IllegalArgumentException.class)
57 | public void shouldThrowAnExceptionWhenStringIsEmpty() {
58 | Preconditions.checkNotNullOrEmpty("", MSG_STRING_IS_NULL);
59 | }
60 |
61 | @Test
62 | public void shouldNotThrowAnythingWhenStringIsNotEmpty() {
63 | Preconditions.checkNotNullOrEmpty("notEmpty", MSG_STRING_IS_NULL);
64 | }
65 |
66 | @Test(expected = IllegalArgumentException.class)
67 | public void shouldThrowAnExceptionWhenValueIsZero() {
68 | Preconditions.checkGreaterThanZero(0, MSG_VALUE_IS_NOT_GREATER_THAN_ZERO);
69 | }
70 |
71 | @Test(expected = IllegalArgumentException.class)
72 | public void shouldThrowAnExceptionWhenValueLowerThanZero() {
73 | Preconditions.checkGreaterThanZero(-1, MSG_VALUE_IS_NOT_GREATER_THAN_ZERO);
74 | }
75 |
76 | @Test
77 | public void shouldNotThrowAnythingWhenValueIsGreaterThanZero() {
78 | Preconditions.checkGreaterThanZero(1, MSG_VALUE_IS_NOT_GREATER_THAN_ZERO);
79 | }
80 |
81 | @Test(expected = IllegalArgumentException.class)
82 | public void shouldThrowAnExceptionWhenValueLowerThanZeroForGreaterOrEqualCheck() {
83 | Preconditions.checkGreaterOrEqualToZero(-1, MSG_VALUE_IS_NOT_GREATER_THAN_ZERO);
84 | }
85 |
86 | @Test
87 | public void shouldNotThrowAnythingWhenValueIsGreaterThanZeroForGreaterOrEqualCheck() {
88 | Preconditions.checkGreaterOrEqualToZero(1, MSG_VALUE_IS_NOT_GREATER_THAN_ZERO);
89 | }
90 |
91 | @Test
92 | public void shouldNotThrowAnythingWhenValueIsEqualToZero() {
93 | Preconditions.checkGreaterOrEqualToZero(0, MSG_VALUE_IS_NOT_GREATER_THAN_ZERO);
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/ReactiveNetworkTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2;
17 |
18 | import android.app.Application;
19 | import android.content.Context;
20 | import android.net.NetworkInfo;
21 | import androidx.annotation.NonNull;
22 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings;
23 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy;
24 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.DefaultErrorHandler;
25 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
26 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.SocketInternetObservingStrategy;
27 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
28 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy.LollipopNetworkObservingStrategy;
29 | import io.reactivex.Observable;
30 | import io.reactivex.Single;
31 | import java.lang.reflect.Method;
32 | import org.junit.Test;
33 | import org.junit.runner.RunWith;
34 | import org.robolectric.RobolectricTestRunner;
35 | import org.robolectric.RuntimeEnvironment;
36 | import org.robolectric.annotation.Config;
37 | import org.robolectric.shadows.ShadowConnectivityManager;
38 |
39 | import static com.google.common.truth.Truth.assertThat;
40 |
41 | @RunWith(RobolectricTestRunner.class)
42 | @Config(shadows = ShadowConnectivityManager.class)
43 | @SuppressWarnings("NullAway") public class ReactiveNetworkTest {
44 |
45 | private static final String TEST_VALID_HOST = "www.test.com";
46 | private static final int TEST_VALID_PORT = 80;
47 | private static final int TEST_VALID_TIMEOUT = 1000;
48 | private static final int TEST_VALID_INTERVAL = 1000;
49 | private static final int TEST_VALID_INITIAL_INTERVAL = 1000;
50 | private static final int TEST_VALID_HTTP_RESPONSE = 204;
51 |
52 | @Test public void testReactiveNetworkObjectShouldNotBeNull() {
53 | // given
54 | ReactiveNetwork reactiveNetwork;
55 |
56 | // when
57 | reactiveNetwork = ReactiveNetwork.create();
58 |
59 | // then
60 | assertThat(reactiveNetwork).isNotNull();
61 | }
62 |
63 | @Test public void observeNetworkConnectivityShouldNotBeNull() {
64 | // given
65 | networkConnectivityObservableShouldNotBeNull();
66 | }
67 |
68 | @Test @Config(sdk = 23) public void observeNetworkConnectivityShouldNotBeNullForMarshmallow() {
69 | // given
70 | networkConnectivityObservableShouldNotBeNull();
71 | }
72 |
73 | @Test @Config(sdk = 21) public void observeNetworkConnectivityShouldNotBeNullForLollipop() {
74 | networkConnectivityObservableShouldNotBeNull();
75 | }
76 |
77 | private void networkConnectivityObservableShouldNotBeNull() {
78 | // given
79 | final Application context = RuntimeEnvironment.getApplication();
80 | //final ConnectivityManager connectivityManagerMock = (ConnectivityManager) context
81 | // .getSystemService(Context.CONNECTIVITY_SERVICE);
82 | //
83 | //shadowOf(connectivityManagerMock);
84 |
85 | // when
86 | Observable observable;
87 | observable = ReactiveNetwork.observeNetworkConnectivity(context);
88 |
89 | // then
90 | assertThat(observable).isNotNull();
91 | }
92 |
93 | @Test public void observeNetworkConnectivityWithStrategyShouldNotBeNull() {
94 | // given
95 | final Application context = RuntimeEnvironment.getApplication();
96 |
97 | NetworkObservingStrategy strategy = new LollipopNetworkObservingStrategy();
98 |
99 | // when
100 | Observable observable;
101 | observable = ReactiveNetwork.observeNetworkConnectivity(context, strategy);
102 |
103 | // then
104 | assertThat(observable).isNotNull();
105 | }
106 |
107 | @Test public void observeInternetConnectivityDefaultShouldNotBeNull() {
108 | // given
109 | Observable observable;
110 |
111 | // when
112 | observable = ReactiveNetwork.observeInternetConnectivity();
113 |
114 | // then
115 | assertThat(observable).isNotNull();
116 | }
117 |
118 | @Test public void observeNetworkConnectivityShouldBeConnectedOnStartWhenNetworkIsAvailable() {
119 | // given
120 | final Application context = RuntimeEnvironment.getApplication();
121 |
122 | // when
123 | Connectivity connectivity = ReactiveNetwork.observeNetworkConnectivity(context).blockingFirst();
124 |
125 | // then
126 | assertThat(connectivity.state()).isEqualTo(NetworkInfo.State.CONNECTED);
127 | }
128 |
129 | @Test(expected = IllegalArgumentException.class)
130 | public void observeNetworkConnectivityShouldThrowAnExceptionForNullContext() {
131 | // given
132 | final Context context = null;
133 | final NetworkObservingStrategy strategy = new LollipopNetworkObservingStrategy();
134 |
135 | // when
136 | //noinspection ConstantConditions
137 | ReactiveNetwork.observeNetworkConnectivity(context, strategy);
138 |
139 | // then an exception is thrown
140 | }
141 |
142 | @Test(expected = IllegalArgumentException.class)
143 | public void observeNetworkConnectivityShouldThrowAnExceptionForNullStrategy() {
144 | // given
145 | final Context context = RuntimeEnvironment.application;
146 | final NetworkObservingStrategy strategy = null;
147 |
148 | // when
149 | ReactiveNetwork.observeNetworkConnectivity(context, strategy);
150 |
151 | // then an exception is thrown
152 | }
153 |
154 | @Test(expected = IllegalArgumentException.class)
155 | public void observeInternetConnectivityShouldThrowAnExceptionWhenStrategyIsNull() {
156 | // given
157 | final InternetObservingStrategy strategy = null;
158 | final ErrorHandler errorHandler = new DefaultErrorHandler();
159 |
160 | // when
161 | //noinspection ConstantConditions
162 | ReactiveNetwork.observeInternetConnectivity(strategy, TEST_VALID_INITIAL_INTERVAL,
163 | TEST_VALID_INTERVAL, TEST_VALID_HOST, TEST_VALID_PORT, TEST_VALID_TIMEOUT,
164 | TEST_VALID_HTTP_RESPONSE, errorHandler);
165 |
166 | // then an exception is thrown
167 | }
168 |
169 | @Test public void observeInternetConnectivityShouldNotThrowAnExceptionWhenStrategyIsNotNull() {
170 | // given
171 | final InternetObservingStrategy strategy = new SocketInternetObservingStrategy();
172 | final ErrorHandler errorHandler = new DefaultErrorHandler();
173 |
174 | // when
175 | final Observable observable =
176 | ReactiveNetwork.observeInternetConnectivity(strategy, TEST_VALID_INITIAL_INTERVAL,
177 | TEST_VALID_INTERVAL, TEST_VALID_HOST, TEST_VALID_PORT, TEST_VALID_TIMEOUT,
178 | TEST_VALID_HTTP_RESPONSE, errorHandler);
179 |
180 | // then
181 | assertThat(observable).isNotNull();
182 | }
183 |
184 | @Test(expected = IllegalArgumentException.class)
185 | public void checkInternetConnectivityShouldThrowAnExceptionWhenStrategyIsNull() {
186 | // given
187 | final ErrorHandler errorHandler = new DefaultErrorHandler();
188 |
189 | // when
190 | ReactiveNetwork.checkInternetConnectivity(null, TEST_VALID_HOST, TEST_VALID_PORT,
191 | TEST_VALID_TIMEOUT, TEST_VALID_HTTP_RESPONSE, errorHandler);
192 |
193 | // then an exception is thrown
194 | }
195 |
196 | @Test public void checkInternetConnectivityShouldNotThrowAnExceptionWhenStrategyIsNotNull() {
197 | // given
198 | final InternetObservingStrategy strategy = new SocketInternetObservingStrategy();
199 | final ErrorHandler errorHandler = new DefaultErrorHandler();
200 |
201 | // when
202 | final Single single =
203 | ReactiveNetwork.checkInternetConnectivity(strategy, TEST_VALID_HOST, TEST_VALID_PORT,
204 | TEST_VALID_TIMEOUT, TEST_VALID_HTTP_RESPONSE, errorHandler);
205 |
206 | // then
207 | assertThat(single).isNotNull();
208 | }
209 |
210 | @Test
211 | public void shouldObserveInternetConnectivityWithCustomSettings() {
212 | // given
213 | final int initialInterval = 1;
214 | final int interval = 2;
215 | final String host = "www.test.com";
216 | int port = 90;
217 | int timeout = 3;
218 | ErrorHandler testErrorHandler = createTestErrorHandler();
219 | InternetObservingStrategy strategy = createTestInternetObservingStrategy();
220 |
221 | // when
222 | InternetObservingSettings settings = InternetObservingSettings.builder()
223 | .initialInterval(initialInterval)
224 | .interval(interval)
225 | .host(host)
226 | .port(port)
227 | .timeout(timeout)
228 | .errorHandler(testErrorHandler)
229 | .strategy(strategy)
230 | .build();
231 |
232 | // then
233 | Observable observable = ReactiveNetwork.observeInternetConnectivity(settings);
234 | assertThat(observable).isNotNull();
235 | }
236 |
237 | @Test
238 | public void shouldCheckInternetConnectivityWithCustomSettings() {
239 | // given
240 | final int initialInterval = 1;
241 | final int interval = 2;
242 | final String host = "www.test.com";
243 | int port = 90;
244 | int timeout = 3;
245 | int httpResponse = 200;
246 | ErrorHandler testErrorHandler = createTestErrorHandler();
247 | InternetObservingStrategy strategy = createTestInternetObservingStrategy();
248 |
249 | // when
250 | InternetObservingSettings settings = InternetObservingSettings.builder()
251 | .initialInterval(initialInterval)
252 | .interval(interval)
253 | .host(host)
254 | .port(port)
255 | .timeout(timeout)
256 | .httpResponse(httpResponse)
257 | .errorHandler(testErrorHandler)
258 | .strategy(strategy)
259 | .build();
260 |
261 | // then
262 | Single single = ReactiveNetwork.checkInternetConnectivity(settings);
263 | assertThat(single).isNotNull();
264 | }
265 |
266 | @NonNull private InternetObservingStrategy createTestInternetObservingStrategy() {
267 | return new InternetObservingStrategy() {
268 | @Override public Observable observeInternetConnectivity(int initialIntervalInMs,
269 | int intervalInMs, String host, int port, int timeoutInMs, int httpResponse,
270 | ErrorHandler errorHandler) {
271 | return Observable.empty();
272 | }
273 |
274 | @Override public Single checkInternetConnectivity(String host, int port,
275 | int timeoutInMs, int httpResponse, ErrorHandler errorHandler) {
276 | return Single.fromCallable(() -> true);
277 | }
278 |
279 | @Override public String getDefaultPingHost() {
280 | return null;
281 | }
282 | };
283 | }
284 |
285 | @NonNull private ErrorHandler createTestErrorHandler() {
286 | return (exception, message) -> {
287 | };
288 | }
289 |
290 | @Test
291 | public void shouldHaveJustSevenMethodsInPublicApi() {
292 | // given
293 | Class extends ReactiveNetwork> clazz = ReactiveNetwork.create().getClass();
294 | final int predefinedNumberOfMethods = 9;
295 | final int publicMethodsInApi = 7; // this number can be increased only in reasonable case
296 |
297 | // when
298 | Method[] methods = clazz.getMethods();
299 |
300 | // then
301 | assertThat(methods.length).isEqualTo(predefinedNumberOfMethods + publicMethodsInApi);
302 | }
303 | }
304 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/InternetObservingSettingsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing;
17 |
18 | import androidx.annotation.NonNull;
19 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.DefaultErrorHandler;
20 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
21 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.SocketInternetObservingStrategy;
22 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy;
23 | import org.junit.Test;
24 | import org.junit.runner.RunWith;
25 | import org.robolectric.RobolectricTestRunner;
26 |
27 | import static com.google.common.truth.Truth.assertThat;
28 |
29 | @RunWith(RobolectricTestRunner.class)
30 | public class InternetObservingSettingsTest {
31 |
32 | @Test
33 | public void shouldCreateSettings() {
34 | // when
35 | InternetObservingSettings settings = InternetObservingSettings.create();
36 |
37 | // then
38 | assertThat(settings).isNotNull();
39 | }
40 |
41 | @Test
42 | public void shouldBuildSettingsWithDefaultValues() {
43 | // when
44 | InternetObservingSettings settings = InternetObservingSettings.create();
45 |
46 | // then
47 | assertThat(settings.initialInterval()).isEqualTo(0);
48 | assertThat(settings.interval()).isEqualTo(2000);
49 | assertThat(settings.host()).isEqualTo("http://clients3.google.com/generate_204");
50 | assertThat(settings.port()).isEqualTo(80);
51 | assertThat(settings.timeout()).isEqualTo(2000);
52 | assertThat(settings.httpResponse()).isEqualTo(204);
53 | assertThat(settings.errorHandler()).isInstanceOf(DefaultErrorHandler.class);
54 | assertThat(settings.strategy()).isInstanceOf(WalledGardenInternetObservingStrategy.class);
55 | }
56 |
57 | @Test
58 | public void shouldBuildSettings() {
59 | // given
60 | final int initialInterval = 1;
61 | final int interval = 2;
62 | final String host = "www.test.com";
63 | int port = 90;
64 | int timeout = 3;
65 | int httpResponse = 200;
66 | ErrorHandler testErrorHandler = createTestErrorHandler();
67 | SocketInternetObservingStrategy strategy = new SocketInternetObservingStrategy();
68 |
69 | // when
70 | InternetObservingSettings settings = InternetObservingSettings.builder()
71 | .initialInterval(initialInterval)
72 | .interval(interval)
73 | .host(host)
74 | .port(port)
75 | .timeout(timeout)
76 | .httpResponse(httpResponse)
77 | .errorHandler(testErrorHandler)
78 | .strategy(strategy)
79 | .build();
80 |
81 | // then
82 | assertThat(settings.initialInterval()).isEqualTo(initialInterval);
83 | assertThat(settings.interval()).isEqualTo(interval);
84 | assertThat(settings.host()).isEqualTo(host);
85 | assertThat(settings.port()).isEqualTo(port);
86 | assertThat(settings.timeout()).isEqualTo(timeout);
87 | assertThat(settings.httpResponse()).isEqualTo(httpResponse);
88 | assertThat(settings.errorHandler()).isNotNull();
89 | assertThat(settings.errorHandler()).isNotInstanceOf(DefaultErrorHandler.class);
90 | assertThat(settings.strategy()).isInstanceOf(SocketInternetObservingStrategy.class);
91 | }
92 |
93 | @NonNull private ErrorHandler createTestErrorHandler() {
94 | return (exception, message) -> { };
95 | }
96 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/error/DefaultErrorHandlerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error;
17 |
18 | import org.junit.Rule;
19 | import org.junit.Test;
20 | import org.junit.runner.RunWith;
21 | import org.mockito.Spy;
22 | import org.mockito.junit.MockitoJUnit;
23 | import org.mockito.junit.MockitoRule;
24 | import org.robolectric.RobolectricTestRunner;
25 |
26 | import static org.mockito.Mockito.times;
27 | import static org.mockito.Mockito.verify;
28 |
29 | @RunWith(RobolectricTestRunner.class)
30 | @SuppressWarnings("NullAway") public class DefaultErrorHandlerTest {
31 |
32 | @Rule public MockitoRule rule = MockitoJUnit.rule();
33 | @Spy private DefaultErrorHandler handler = new DefaultErrorHandler();
34 |
35 | @Test public void shouldHandleErrorDuringClosingSocket() {
36 | // given
37 | final String errorMsg = "Could not close the socket";
38 | final Exception exception = new Exception(errorMsg);
39 |
40 | // when
41 | handler.handleError(exception, errorMsg);
42 |
43 | // then
44 | verify(handler, times(1)).handleError(exception, errorMsg);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/strategy/SocketInternetObservingStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy;
17 |
18 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
19 | import io.reactivex.Observable;
20 | import io.reactivex.Single;
21 | import java.io.IOException;
22 | import java.net.InetSocketAddress;
23 | import java.net.Socket;
24 | import org.junit.Rule;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.mockito.Mock;
28 | import org.mockito.Spy;
29 | import org.mockito.junit.MockitoJUnit;
30 | import org.mockito.junit.MockitoRule;
31 | import org.robolectric.RobolectricTestRunner;
32 |
33 | import static com.google.common.truth.Truth.assertThat;
34 | import static org.mockito.Mockito.doThrow;
35 | import static org.mockito.Mockito.times;
36 | import static org.mockito.Mockito.verify;
37 | import static org.mockito.Mockito.when;
38 |
39 | @RunWith(RobolectricTestRunner.class)
40 | @SuppressWarnings({ "PMD", "NullAway" }) public class SocketInternetObservingStrategyTest {
41 |
42 | private static final int INITIAL_INTERVAL_IN_MS = 0;
43 | private static final int INTERVAL_IN_MS = 2000;
44 | private static final int PORT = 80;
45 | private static final int TIMEOUT_IN_MS = 30;
46 | private static final int HTTP_RESPONSE = 204;
47 | private static final String HOST_WITH_HTTP = "http://www.website.com";
48 | private static final String HOST_WITHOUT_HTTP = "www.website.com";
49 |
50 | @Rule public MockitoRule rule = MockitoJUnit.rule();
51 | @Spy private SocketInternetObservingStrategy strategy;
52 | @Mock private ErrorHandler errorHandler;
53 | @Mock private Socket socket;
54 |
55 | private String getHost() {
56 | return strategy.getDefaultPingHost();
57 | }
58 |
59 | @Test public void shouldBeConnectedToTheInternet() {
60 | // given
61 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, errorHandler)).thenReturn(true);
62 |
63 | // when
64 | final Observable observable =
65 | strategy.observeInternetConnectivity(INITIAL_INTERVAL_IN_MS, INTERVAL_IN_MS, getHost(),
66 | PORT, TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandler);
67 |
68 | boolean isConnected = observable.blockingFirst();
69 |
70 | // then
71 | assertThat(isConnected).isTrue();
72 | }
73 |
74 | @Test public void shouldNotBeConnectedToTheInternet() {
75 | // given
76 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, errorHandler)).thenReturn(false);
77 |
78 | // when
79 | final Observable observable =
80 | strategy.observeInternetConnectivity(INITIAL_INTERVAL_IN_MS, INTERVAL_IN_MS, getHost(),
81 | PORT, TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandler);
82 |
83 | boolean isConnected = observable.blockingFirst();
84 |
85 | // then
86 | assertThat(isConnected).isFalse();
87 | }
88 |
89 | @Test public void shouldNotBeConnectedToTheInternetWhenSocketThrowsAnExceptionOnConnect()
90 | throws IOException {
91 | // given
92 | final InetSocketAddress address = new InetSocketAddress(getHost(), PORT);
93 | doThrow(new IOException()).when(socket).connect(address, TIMEOUT_IN_MS);
94 |
95 | // when
96 | final boolean isConnected =
97 | strategy.isConnected(socket, getHost(), PORT, TIMEOUT_IN_MS, errorHandler);
98 |
99 | // then
100 | assertThat(isConnected).isFalse();
101 | }
102 |
103 | @Test public void shouldHandleAnExceptionThrownDuringClosingTheSocket() throws IOException {
104 | // given
105 | final String errorMsg = "Could not close the socket";
106 | final IOException givenException = new IOException(errorMsg);
107 | doThrow(givenException).when(socket).close();
108 |
109 | // when
110 | strategy.isConnected(socket, getHost(), PORT, TIMEOUT_IN_MS, errorHandler);
111 |
112 | // then
113 | verify(errorHandler, times(1)).handleError(givenException, errorMsg);
114 | }
115 |
116 | @Test public void shouldBeConnectedToTheInternetViaSingle() {
117 | // given
118 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, errorHandler)).thenReturn(true);
119 |
120 | // when
121 | final Single observable =
122 | strategy.checkInternetConnectivity(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
123 | errorHandler);
124 |
125 | boolean isConnected = observable.blockingGet();
126 |
127 | // then
128 | assertThat(isConnected).isTrue();
129 | }
130 |
131 | @Test public void shouldNotBeConnectedToTheInternetViaSingle() {
132 | // given
133 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, errorHandler)).thenReturn(false);
134 |
135 | // when
136 | final Single observable =
137 | strategy.checkInternetConnectivity(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
138 | errorHandler);
139 |
140 | boolean isConnected = observable.blockingGet();
141 |
142 | // then
143 | assertThat(isConnected).isFalse();
144 | }
145 |
146 | @Test public void shouldNotTransformHost() {
147 | // when
148 | String transformedHost = strategy.adjustHost(HOST_WITHOUT_HTTP);
149 |
150 | // then
151 | assertThat(transformedHost).isEqualTo(HOST_WITHOUT_HTTP);
152 | }
153 |
154 | @Test public void shouldRemoveHttpProtocolFromHost() {
155 | // when
156 | String transformedHost = strategy.adjustHost(HOST_WITH_HTTP);
157 |
158 | // then
159 | assertThat(transformedHost).isEqualTo(HOST_WITHOUT_HTTP);
160 | }
161 |
162 | @Test public void shouldRemoveHttpsProtocolFromHost() {
163 | // when
164 | String transformedHost = strategy.adjustHost(HOST_WITH_HTTP);
165 |
166 | // then
167 | assertThat(transformedHost).isEqualTo(HOST_WITHOUT_HTTP);
168 | }
169 |
170 | @Test @SuppressWarnings("CheckReturnValue")
171 | public void shouldAdjustHostDuringCheckingConnectivity() {
172 | // given
173 | final String host = getHost();
174 | when(strategy.isConnected(host, PORT, TIMEOUT_IN_MS, errorHandler)).thenReturn(true);
175 |
176 | // when
177 | strategy.observeInternetConnectivity(INITIAL_INTERVAL_IN_MS, INTERVAL_IN_MS, host, PORT,
178 | TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandler).blockingFirst();
179 |
180 | // then
181 | verify(strategy).adjustHost(host);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/internet/observing/strategy/WalledGardenInternetObservingStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy;
17 |
18 | import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
19 | import io.reactivex.Observable;
20 | import io.reactivex.Single;
21 | import java.io.IOException;
22 | import java.net.HttpURLConnection;
23 | import org.junit.Rule;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.mockito.Mock;
27 | import org.mockito.Spy;
28 | import org.mockito.junit.MockitoJUnit;
29 | import org.mockito.junit.MockitoRule;
30 | import org.robolectric.RobolectricTestRunner;
31 | import org.robolectric.annotation.Config;
32 |
33 | import static com.google.common.truth.Truth.assertThat;
34 | import static org.mockito.Mockito.verify;
35 | import static org.mockito.Mockito.when;
36 |
37 | @Config(manifest = Config.NONE)
38 | @RunWith(RobolectricTestRunner.class)
39 | @SuppressWarnings("NullAway") public class WalledGardenInternetObservingStrategyTest {
40 |
41 | private static final int INITIAL_INTERVAL_IN_MS = 0;
42 | private static final int INTERVAL_IN_MS = 2000;
43 | private static final int PORT = 80;
44 | private static final int TIMEOUT_IN_MS = 30;
45 | private static final int HTTP_RESPONSE = 204;
46 | private static final String HOST_WITH_HTTP = "http://www.website.com";
47 | private static final String HOST_WITH_HTTPS = "https://www.website.com";
48 | private static final String HOST_WITHOUT_HTTPS = "www.website.com";
49 |
50 | @Rule public MockitoRule rule = MockitoJUnit.rule();
51 | @Mock private ErrorHandler errorHandler;
52 | @Spy private WalledGardenInternetObservingStrategy strategy;
53 |
54 | private String getHost() {
55 | return strategy.getDefaultPingHost();
56 | }
57 |
58 | @Test public void shouldBeConnectedToTheInternet() {
59 | // given
60 | final ErrorHandler errorHandlerStub = createErrorHandlerStub();
61 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
62 | errorHandlerStub)).thenReturn(true);
63 |
64 | // when
65 | final Observable observable =
66 | strategy.observeInternetConnectivity(INITIAL_INTERVAL_IN_MS, INTERVAL_IN_MS, getHost(),
67 | PORT, TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandlerStub);
68 |
69 | boolean isConnected = observable.blockingFirst();
70 |
71 | // then
72 | assertThat(isConnected).isTrue();
73 | }
74 |
75 | @Test public void shouldNotBeConnectedToTheInternet() {
76 | // given
77 | final ErrorHandler errorHandlerStub = createErrorHandlerStub();
78 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
79 | errorHandlerStub)).thenReturn(false);
80 |
81 | // when
82 | final Observable observable =
83 | strategy.observeInternetConnectivity(INITIAL_INTERVAL_IN_MS, INTERVAL_IN_MS, getHost(),
84 | PORT, TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandlerStub);
85 |
86 | boolean isConnected = observable.blockingFirst();
87 |
88 | // then
89 | assertThat(isConnected).isFalse();
90 | }
91 |
92 | @Test public void shouldBeConnectedToTheInternetViaSingle() {
93 | // given
94 | final ErrorHandler errorHandlerStub = createErrorHandlerStub();
95 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
96 | errorHandlerStub)).thenReturn(true);
97 |
98 | // when
99 | final Single observable =
100 | strategy.checkInternetConnectivity(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
101 | errorHandlerStub);
102 |
103 | boolean isConnected = observable.blockingGet();
104 |
105 | // then
106 | assertThat(isConnected).isTrue();
107 | }
108 |
109 | @Test public void shouldNotBeConnectedToTheInternetViaSingle() {
110 | // given
111 | final ErrorHandler errorHandlerStub = createErrorHandlerStub();
112 | when(strategy.isConnected(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
113 | errorHandlerStub)).thenReturn(false);
114 |
115 | // when
116 | final Single observable =
117 | strategy.checkInternetConnectivity(getHost(), PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
118 | errorHandlerStub);
119 |
120 | boolean isConnected = observable.blockingGet();
121 |
122 | // then
123 | assertThat(isConnected).isFalse();
124 | }
125 |
126 | @Test public void shouldCreateHttpUrlConnection() throws IOException {
127 | // given
128 | final String parsedDefaultHost = "clients3.google.com";
129 |
130 | // when
131 | HttpURLConnection connection = strategy.createHttpUrlConnection(getHost(), PORT, TIMEOUT_IN_MS);
132 |
133 | // then
134 | assertThat(connection).isNotNull();
135 | assertThat(connection.getURL().getHost()).isEqualTo(parsedDefaultHost);
136 | assertThat(connection.getURL().getPort()).isEqualTo(PORT);
137 | assertThat(connection.getConnectTimeout()).isEqualTo(TIMEOUT_IN_MS);
138 | assertThat(connection.getReadTimeout()).isEqualTo(TIMEOUT_IN_MS);
139 | assertThat(connection.getInstanceFollowRedirects()).isFalse();
140 | assertThat(connection.getUseCaches()).isFalse();
141 | }
142 |
143 | @Test public void shouldHandleAnExceptionWhileCreatingHttpUrlConnection() throws IOException {
144 | // given
145 | final String errorMsg = "Could not establish connection with WalledGardenStrategy";
146 | final IOException givenException = new IOException(errorMsg);
147 | when(strategy.createHttpUrlConnection(HOST_WITH_HTTP, PORT, TIMEOUT_IN_MS)).thenThrow(
148 | givenException);
149 |
150 | // when
151 | strategy.isConnected(HOST_WITH_HTTP, PORT, TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandler);
152 |
153 | // then
154 | verify(errorHandler).handleError(givenException, errorMsg);
155 | }
156 |
157 | @Test public void shouldCreateHttpsUrlConnection() throws IOException {
158 | // given
159 | final String parsedDefaultHost = "clients3.google.com";
160 |
161 | // when
162 | HttpURLConnection connection =
163 | strategy.createHttpsUrlConnection("https://clients3.google.com", PORT, TIMEOUT_IN_MS);
164 |
165 | // then
166 | assertThat(connection).isNotNull();
167 | assertThat(connection.getURL().getHost()).isEqualTo(parsedDefaultHost);
168 | assertThat(connection.getURL().getPort()).isEqualTo(PORT);
169 | assertThat(connection.getConnectTimeout()).isEqualTo(TIMEOUT_IN_MS);
170 | assertThat(connection.getReadTimeout()).isEqualTo(TIMEOUT_IN_MS);
171 | assertThat(connection.getInstanceFollowRedirects()).isFalse();
172 | assertThat(connection.getUseCaches()).isFalse();
173 | }
174 |
175 | @Test public void shouldHandleAnExceptionWhileCreatingHttpsUrlConnection() throws IOException {
176 | // given
177 | final String errorMsg = "Could not establish connection with WalledGardenStrategy";
178 | final IOException givenException = new IOException(errorMsg);
179 | final String host = "https://clients3.google.com";
180 | when(strategy.createHttpsUrlConnection(host, PORT, TIMEOUT_IN_MS)).thenThrow(
181 | givenException);
182 |
183 | // when
184 | strategy.isConnected(host, PORT, TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandler);
185 |
186 | // then
187 | verify(errorHandler).handleError(givenException, errorMsg);
188 | }
189 |
190 | @Test public void shouldNotTransformHttpHost() {
191 | // when
192 | String transformedHost = strategy.adjustHost(HOST_WITH_HTTPS);
193 |
194 | // then
195 | assertThat(transformedHost).isEqualTo(HOST_WITH_HTTPS);
196 | }
197 |
198 | @Test public void shouldNotTransformHttpsHost() {
199 | // when
200 | String transformedHost = strategy.adjustHost(HOST_WITH_HTTPS);
201 |
202 | // then
203 | assertThat(transformedHost).isEqualTo(HOST_WITH_HTTPS);
204 | }
205 |
206 | @Test public void shouldAddHttpsProtocolToHost() {
207 | // when
208 | String transformedHost = strategy.adjustHost(HOST_WITHOUT_HTTPS);
209 |
210 | // then
211 | assertThat(transformedHost).isEqualTo(HOST_WITH_HTTPS);
212 | }
213 |
214 | @Test @SuppressWarnings("CheckReturnValue")
215 | public void shouldAdjustHostWhileCheckingConnectivity() {
216 | // given
217 | final ErrorHandler errorHandlerStub = createErrorHandlerStub();
218 | final String host = getHost();
219 | when(strategy.isConnected(host, PORT, TIMEOUT_IN_MS, HTTP_RESPONSE,
220 | errorHandlerStub)).thenReturn(
221 | true);
222 |
223 | // when
224 | strategy.observeInternetConnectivity(INITIAL_INTERVAL_IN_MS, INTERVAL_IN_MS, host, PORT,
225 | TIMEOUT_IN_MS, HTTP_RESPONSE, errorHandlerStub).blockingFirst();
226 |
227 | // then
228 | verify(strategy).adjustHost(host);
229 | }
230 |
231 | private ErrorHandler createErrorHandlerStub() {
232 | return new ErrorHandler() {
233 | @Override public void handleError(Exception exception, String message) {
234 | }
235 | };
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/NetworkObservingStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.net.NetworkInfo;
21 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
22 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy.LollipopNetworkObservingStrategy;
23 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy.PreLollipopNetworkObservingStrategy;
24 | import io.reactivex.disposables.Disposable;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.robolectric.RobolectricTestRunner;
28 | import org.robolectric.RuntimeEnvironment;
29 | import static com.google.common.truth.Truth.assertThat;
30 |
31 | @RunWith(RobolectricTestRunner.class)
32 | @SuppressWarnings("NullAway") public class NetworkObservingStrategyTest {
33 |
34 | @Test public void lollipopObserveNetworkConnectivityShouldBeConnectedWhenNetworkIsAvailable() {
35 | // given
36 | final NetworkObservingStrategy strategy = new LollipopNetworkObservingStrategy();
37 |
38 | // when
39 | assertThatIsConnected(strategy);
40 | }
41 |
42 | @Test public void preLollipopObserveNetworkConnectivityShouldBeConnectedWhenNetworkIsAvailable() {
43 | // given
44 | final NetworkObservingStrategy strategy = new PreLollipopNetworkObservingStrategy();
45 |
46 | // when
47 | assertThatIsConnected(strategy);
48 | }
49 |
50 | @SuppressLint("CheckResult")
51 | private void assertThatIsConnected(NetworkObservingStrategy strategy) {
52 | // given
53 | final Context context = RuntimeEnvironment.getApplication().getApplicationContext();
54 |
55 | //when
56 | Disposable disposable = strategy.observeNetworkConnectivity(context)
57 | .subscribe(
58 | (@SuppressLint("CheckResult") Connectivity connectivity) -> {
59 | // then
60 | assertThat(connectivity.state()).isEqualTo(NetworkInfo.State.CONNECTED);
61 | });
62 |
63 | disposable.dispose();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/strategy/LollipopNetworkObservingStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy;
17 |
18 | import android.app.Application;
19 | import android.content.Context;
20 | import android.net.NetworkInfo;
21 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
22 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
23 | import io.reactivex.Observable;
24 | import io.reactivex.observers.TestObserver;
25 | import org.junit.Rule;
26 | import org.junit.Test;
27 | import org.junit.runner.RunWith;
28 | import org.mockito.Spy;
29 | import org.mockito.junit.MockitoJUnit;
30 | import org.mockito.junit.MockitoRule;
31 | import org.robolectric.RobolectricTestRunner;
32 | import org.robolectric.RuntimeEnvironment;
33 |
34 | import static com.google.common.truth.Truth.assertThat;
35 | import static org.mockito.Mockito.times;
36 | import static org.mockito.Mockito.verify;
37 |
38 | @RunWith(RobolectricTestRunner.class)
39 | @SuppressWarnings("NullAway") public class LollipopNetworkObservingStrategyTest {
40 |
41 | @Rule public MockitoRule rule = MockitoJUnit.rule();
42 | @Spy private NetworkObservingStrategy strategy = new LollipopNetworkObservingStrategy();
43 |
44 | @Test public void shouldObserveConnectivity() {
45 | // given
46 | final NetworkObservingStrategy strategy = new LollipopNetworkObservingStrategy();
47 | final Context context = RuntimeEnvironment.getApplication().getApplicationContext();
48 |
49 | // when
50 | Connectivity connectivity = strategy.observeNetworkConnectivity(context).blockingFirst();
51 |
52 | // then
53 | assertThat(connectivity.state()).isEqualTo(NetworkInfo.State.CONNECTED);
54 | }
55 |
56 | @Test public void shouldStopObservingConnectivity() {
57 | // given
58 | final NetworkObservingStrategy strategy = new LollipopNetworkObservingStrategy();
59 | final Application context = RuntimeEnvironment.getApplication();
60 | final Observable observable = strategy.observeNetworkConnectivity(context);
61 | final TestObserver observer = new TestObserver<>();
62 |
63 | // when
64 | observable.subscribe(observer);
65 | observer.dispose();
66 |
67 | // then
68 | assertThat(observer.isDisposed()).isTrue();
69 | }
70 |
71 | @Test public void shouldCallOnError() {
72 | // given
73 | final String message = "error message";
74 | final Exception exception = new Exception();
75 |
76 | // when
77 | strategy.onError(message, exception);
78 |
79 | // then
80 | verify(strategy, times(1)).onError(message, exception);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/library/src/test/java/com/github/pwittchen/reactivenetwork/library/rx2/network/observing/strategy/PreLollipopNetworkObservingStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Piotr Wittchen
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.github.pwittchen.reactivenetwork.library.rx2.network.observing.strategy;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.app.Application;
20 | import android.content.BroadcastReceiver;
21 | import android.content.Context;
22 | import android.net.NetworkInfo;
23 | import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity;
24 | import com.github.pwittchen.reactivenetwork.library.rx2.network.observing.NetworkObservingStrategy;
25 | import io.reactivex.Observable;
26 | import io.reactivex.observers.TestObserver;
27 | import org.junit.Rule;
28 | import org.junit.Test;
29 | import org.junit.runner.RunWith;
30 | import org.mockito.Mock;
31 | import org.mockito.Spy;
32 | import org.mockito.junit.MockitoJUnit;
33 | import org.mockito.junit.MockitoRule;
34 | import org.robolectric.RobolectricTestRunner;
35 | import org.robolectric.RuntimeEnvironment;
36 | import static com.google.common.truth.Truth.assertThat;
37 | import static org.mockito.ArgumentMatchers.any;
38 | import static org.mockito.ArgumentMatchers.eq;
39 | import static org.mockito.Mockito.spy;
40 | import static org.mockito.Mockito.times;
41 | import static org.mockito.Mockito.verify;
42 |
43 | // We are suppressing PMD here because we want static imports in unit tests
44 | @RunWith(RobolectricTestRunner.class)
45 | @SuppressWarnings({ "PMD", "NullAway" }) public class PreLollipopNetworkObservingStrategyTest {
46 |
47 | @Rule public MockitoRule rule = MockitoJUnit.rule();
48 | @Spy private PreLollipopNetworkObservingStrategy strategy =
49 | new PreLollipopNetworkObservingStrategy();
50 | @Mock private BroadcastReceiver broadcastReceiver;
51 |
52 | @SuppressLint("CheckResult") @Test @SuppressWarnings("CheckReturnValue")
53 | public void shouldObserveConnectivity() {
54 | // given
55 | final NetworkObservingStrategy strategy = new PreLollipopNetworkObservingStrategy();
56 | final Context context = RuntimeEnvironment.application.getApplicationContext();
57 |
58 | // when
59 | strategy.observeNetworkConnectivity(context).subscribe(connectivity -> {
60 | // then
61 | assertThat(connectivity.state()).isEqualTo(NetworkInfo.State.CONNECTED);
62 | });
63 | }
64 |
65 | @Test public void shouldStopObservingConnectivity() {
66 | // given
67 | final NetworkObservingStrategy strategy = new PreLollipopNetworkObservingStrategy();
68 | final Context context = RuntimeEnvironment.application.getApplicationContext();
69 | final Observable observable = strategy.observeNetworkConnectivity(context);
70 | final TestObserver observer = new TestObserver<>();
71 |
72 | // when
73 | observable.subscribe(observer);
74 | observer.dispose();
75 |
76 | // then
77 | assertThat(observer.isDisposed()).isTrue();
78 | }
79 |
80 | @Test public void shouldCallOnError() {
81 | // given
82 | final String message = "error message";
83 | final Exception exception = new Exception();
84 |
85 | // when
86 | strategy.onError(message, exception);
87 |
88 | // then
89 | verify(strategy, times(1)).onError(message, exception);
90 | }
91 |
92 | @Test public void shouldTryToUnregisterReceiver() {
93 | // given
94 | final PreLollipopNetworkObservingStrategy strategy = new PreLollipopNetworkObservingStrategy();
95 | final Application context = spy(RuntimeEnvironment.getApplication());
96 |
97 | // when
98 | strategy.tryToUnregisterReceiver(context, broadcastReceiver);
99 |
100 | // then
101 | verify(context).unregisterReceiver(broadcastReceiver);
102 | }
103 |
104 | @Test public void shouldTryToUnregisterReceiverAfterDispose() {
105 | // given
106 | final Context context = RuntimeEnvironment.getApplication().getApplicationContext();
107 | final TestObserver observer = new TestObserver<>();
108 |
109 | // when
110 | strategy.observeNetworkConnectivity(context).subscribe(observer);
111 | observer.dispose();
112 |
113 | // then
114 | verify(strategy).tryToUnregisterReceiver(eq(context), any(BroadcastReceiver.class));
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/library/src/test/resources/robolectric.properties:
--------------------------------------------------------------------------------
1 | sdk=23
--------------------------------------------------------------------------------
/maven_push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
27 | }
28 |
29 | def getSnapshotRepositoryUrl() {
30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
31 | : "https://oss.sonatype.org/content/repositories/snapshots/"
32 | }
33 |
34 | def getRepositoryUsername() {
35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
36 | }
37 |
38 | def getRepositoryPassword() {
39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
40 | }
41 |
42 | afterEvaluate { project ->
43 | uploadArchives {
44 | repositories {
45 | mavenDeployer {
46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
47 |
48 | pom.groupId = GROUP
49 | pom.artifactId = POM_ARTIFACT_ID
50 | pom.version = VERSION_NAME
51 |
52 | repository(url: getReleaseRepositoryUrl()) {
53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
54 | }
55 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | }
58 |
59 | pom.project {
60 | name POM_NAME
61 | packaging POM_PACKAGING
62 | description POM_DESCRIPTION
63 | url POM_URL
64 |
65 | scm {
66 | url POM_SCM_URL
67 | connection POM_SCM_CONNECTION
68 | developerConnection POM_SCM_DEV_CONNECTION
69 | }
70 |
71 | licenses {
72 | license {
73 | name POM_LICENCE_NAME
74 | url POM_LICENCE_URL
75 | distribution POM_LICENCE_DIST
76 | }
77 | }
78 |
79 | developers {
80 | developer {
81 | id POM_DEVELOPER_ID
82 | name POM_DEVELOPER_NAME
83 | }
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
90 | signing {
91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
92 | sign configurations.archives
93 | }
94 |
95 | task androidJavadocs(type: Javadoc) {
96 | source = android.sourceSets.main.java.srcDirs
97 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
98 | failOnError = false
99 | }
100 |
101 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
102 | classifier = 'javadoc'
103 | from androidJavadocs.destinationDir
104 | }
105 |
106 | task androidSourcesJar(type: Jar) {
107 | classifier = 'sources'
108 | from android.sourceSets.main.java.sourceFiles
109 | }
110 |
111 | artifacts {
112 | archives androidSourcesJar
113 | archives androidJavadocsJar
114 | }
115 | }
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | ./gradlew clean build test check uploadArchives closeAndReleaseRepository
3 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library', ':app-kotlin'
2 |
--------------------------------------------------------------------------------
/update_docs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | git checkout gh-pages
3 | git show RxJava2.x:README.md >docs/RxJava2.x/README.md
4 | git add -A
5 | git commit -m "updating docs"
6 | echo "docs updated, now you can push your changes"
7 |
--------------------------------------------------------------------------------
/update_javadocs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # update javadocs for RxJava2.x
4 | git checkout RxJava2.x
5 | ./gradlew clean androidJavadocs
6 | git checkout gh-pages
7 | rm -rf javadoc/RxJava2.x/*
8 | cp -avr library/build/docs/javadoc/* ./javadoc/RxJava2.x
9 | git add -A
10 | git commit -m "updating JavaDoc for RxJava2.x"
11 | rm -rf library/build/docs
12 | echo "javadocs for RxJava2.x updated"
13 |
14 | echo "javadocs for both RxJava1.x and RxJava2.x updated - now you can push your changes"
15 |
--------------------------------------------------------------------------------