diff --git a/app/build.gradle b/app/build.gradle index ec335e9d6..c549dc39c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,6 +99,7 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(":SubsamplingScaleImageView") + compile project(":ReactiveNetwork") compile "com.android.support:support-v4:$SUPPORT_LIBRARY_VERSION" compile "com.android.support:appcompat-v7:$SUPPORT_LIBRARY_VERSION" @@ -130,7 +131,6 @@ dependencies { compile 'eu.davidea:flexible-adapter:4.2.0' compile 'com.nononsenseapps:filepicker:2.5.1' compile 'com.github.amulyakhare:TextDrawable:558677e' - compile 'com.github.pwittchen:reactivenetwork:0.1.5' compile "org.greenrobot:eventbus:$EVENTBUS_VERSION" apt "org.greenrobot:eventbus-annotation-processor:$EVENTBUS_VERSION" diff --git a/libs/ReactiveNetwork/.gitignore b/libs/ReactiveNetwork/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/libs/ReactiveNetwork/.gitignore @@ -0,0 +1 @@ +/build diff --git a/libs/ReactiveNetwork/build.gradle b/libs/ReactiveNetwork/build.gradle new file mode 100644 index 000000000..e280ca2a6 --- /dev/null +++ b/libs/ReactiveNetwork/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + + defaultConfig { + minSdkVersion 9 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + packagingOptions { + exclude 'LICENSE.txt' + exclude 'META-INF/LICENSE.txt' + } +} + +dependencies { + compile 'io.reactivex:rxjava:1.1.0' + compile 'io.reactivex:rxandroid:1.1.0' + + androidTestCompile 'com.android.support.test:testing-support-lib:0.1' + androidTestCompile('com.google.truth:truth:0.27') { + exclude group: 'junit' // Android has JUnit built in + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.2.1' +} diff --git a/libs/ReactiveNetwork/proguard-rules.pro b/libs/ReactiveNetwork/proguard-rules.pro new file mode 100644 index 000000000..aab0e00bc --- /dev/null +++ b/libs/ReactiveNetwork/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /home/piotr/Android/Sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/libs/ReactiveNetwork/src/androidTest/java/com/github/pwittchen/reactivenetwork/library/ConnectivityStatusTest.java b/libs/ReactiveNetwork/src/androidTest/java/com/github/pwittchen/reactivenetwork/library/ConnectivityStatusTest.java new file mode 100644 index 000000000..e1a6efeae --- /dev/null +++ b/libs/ReactiveNetwork/src/androidTest/java/com/github/pwittchen/reactivenetwork/library/ConnectivityStatusTest.java @@ -0,0 +1,64 @@ +package com.github.pwittchen.reactivenetwork.library; + +import android.support.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import rx.functions.Func1; + +import static com.google.common.truth.Truth.assertThat; + +@RunWith(AndroidJUnit4.class) public class ConnectivityStatusTest { + + @Test public void testStatusShouldBeEqualToGivenValue() { + // given + ConnectivityStatus givenStatus = ConnectivityStatus.WIFI_CONNECTED; + + // when + Func1 equalTo = ConnectivityStatus.isEqualTo(givenStatus); + Boolean shouldBeEqualToGivenStatus = equalTo.call(givenStatus); + + // then + assertThat(shouldBeEqualToGivenStatus).isTrue(); + } + + @Test public void testStatusShouldBeEqualToOneOfGivenMultipleValues() { + // given + ConnectivityStatus mobileConnected = ConnectivityStatus.MOBILE_CONNECTED; + ConnectivityStatus givenStatuses[] = + { ConnectivityStatus.WIFI_CONNECTED, ConnectivityStatus.MOBILE_CONNECTED }; + + // when + Func1 equalTo = ConnectivityStatus.isEqualTo(givenStatuses); + Boolean shouldBeEqualToGivenStatus = equalTo.call(mobileConnected); + + // then + assertThat(shouldBeEqualToGivenStatus).isTrue(); + } + + @Test public void testStatusShouldNotBeEqualToGivenValue() { + // given + ConnectivityStatus oneStatus = ConnectivityStatus.WIFI_CONNECTED; + ConnectivityStatus anotherStatus = ConnectivityStatus.MOBILE_CONNECTED; + + // when + Func1 notEqualTo = ConnectivityStatus.isNotEqualTo(oneStatus); + Boolean shouldBeEqualToGivenStatus = notEqualTo.call(anotherStatus); + + // then + assertThat(shouldBeEqualToGivenStatus).isTrue(); + } + + @Test public void testStatusShouldNotBeEqualToOneOfGivenMultipleValues() { + // given + ConnectivityStatus offline = ConnectivityStatus.OFFLINE; + ConnectivityStatus givenStatuses[] = + { ConnectivityStatus.WIFI_CONNECTED, ConnectivityStatus.MOBILE_CONNECTED }; + + // when + Func1 notEqualTo = ConnectivityStatus.isNotEqualTo(givenStatuses); + Boolean shouldBeEqualToGivenStatus = notEqualTo.call(offline); + + // then + assertThat(shouldBeEqualToGivenStatus).isTrue(); + } +} diff --git a/libs/ReactiveNetwork/src/androidTest/java/com/github/pwittchen/reactivenetwork/library/ReactiveNetworkTest.java b/libs/ReactiveNetwork/src/androidTest/java/com/github/pwittchen/reactivenetwork/library/ReactiveNetworkTest.java new file mode 100644 index 000000000..1e1035cf0 --- /dev/null +++ b/libs/ReactiveNetwork/src/androidTest/java/com/github/pwittchen/reactivenetwork/library/ReactiveNetworkTest.java @@ -0,0 +1,21 @@ +package com.github.pwittchen.reactivenetwork.library; + +import android.support.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.google.common.truth.Truth.assertThat; + +@RunWith(AndroidJUnit4.class) public class ReactiveNetworkTest { + + @Test public void testReactiveNetworkObjectShouldNotBeNull() { + // given + ReactiveNetwork reactiveNetwork; + + // when + reactiveNetwork = new ReactiveNetwork(); + + // then + assertThat(reactiveNetwork).isNotNull(); + } +} diff --git a/libs/ReactiveNetwork/src/main/AndroidManifest.xml b/libs/ReactiveNetwork/src/main/AndroidManifest.xml new file mode 100644 index 000000000..36cc6e15b --- /dev/null +++ b/libs/ReactiveNetwork/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/libs/ReactiveNetwork/src/main/java/com/github/pwittchen/reactivenetwork/library/ConnectivityStatus.java b/libs/ReactiveNetwork/src/main/java/com/github/pwittchen/reactivenetwork/library/ConnectivityStatus.java new file mode 100644 index 000000000..9c6737882 --- /dev/null +++ b/libs/ReactiveNetwork/src/main/java/com/github/pwittchen/reactivenetwork/library/ConnectivityStatus.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 Piotr Wittchen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.pwittchen.reactivenetwork.library; + +import rx.functions.Func1; + +public enum ConnectivityStatus { + UNKNOWN("unknown"), + WIFI_CONNECTED("connected to WiFi"), + WIFI_CONNECTED_HAS_INTERNET("connected to WiFi (Internet available)"), + WIFI_CONNECTED_HAS_NO_INTERNET("connected to WiFi (Internet not available)"), + MOBILE_CONNECTED("connected to mobile network"), + OFFLINE("offline"); + + public final String description; + + ConnectivityStatus(final String description) { + this.description = description; + } + + /** + * Creates a function, which checks + * if single connectivity status or many statuses + * are equal to current status. It can be used inside filter(...) + * method from RxJava + * + * @param statuses many connectivity statuses or single status + * @return Func1 from RxJava + */ + public static Func1 isEqualTo(final ConnectivityStatus... statuses) { + return new Func1() { + @Override public Boolean call(ConnectivityStatus connectivityStatus) { + boolean statuesAreEqual = false; + + for (ConnectivityStatus singleStatus : statuses) { + statuesAreEqual = singleStatus == connectivityStatus; + } + + return statuesAreEqual; + } + }; + } + + /** + * Creates a function, which checks + * if single connectivity status or many statuses + * are not equal to current status. It can be used inside filter(...) + * method from RxJava + * + * @param statuses many connectivity statuses or single status + * @return Func1 from RxJava + */ + public static Func1 isNotEqualTo( + final ConnectivityStatus... statuses) { + return new Func1() { + @Override public Boolean call(ConnectivityStatus connectivityStatus) { + boolean statuesAreNotEqual = false; + + for (ConnectivityStatus singleStatus : statuses) { + statuesAreNotEqual = singleStatus != connectivityStatus; + } + + return statuesAreNotEqual; + } + }; + } + + @Override public String toString() { + return "ConnectivityStatus{" + "description='" + description + '\'' + '}'; + } +} diff --git a/libs/ReactiveNetwork/src/main/java/com/github/pwittchen/reactivenetwork/library/ReactiveNetwork.java b/libs/ReactiveNetwork/src/main/java/com/github/pwittchen/reactivenetwork/library/ReactiveNetwork.java new file mode 100644 index 000000000..c83c10b21 --- /dev/null +++ b/libs/ReactiveNetwork/src/main/java/com/github/pwittchen/reactivenetwork/library/ReactiveNetwork.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2015 Piotr Wittchen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.pwittchen.reactivenetwork.library; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Looper; + +import rx.Observable; +import rx.Scheduler; +import rx.Subscriber; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action0; +import rx.subscriptions.Subscriptions; + +/** + * ReactiveNetwork is an Android library + * listening network connection state and change of the WiFi signal strength + * with RxJava Observables. It can be easily used with RxAndroid. + */ +public class ReactiveNetwork { + private boolean checkInternet = false; + private ConnectivityStatus status = ConnectivityStatus.UNKNOWN; + + /** + * Enables Internet connection check. + * When it's called WIFI_CONNECTED_HAS_INTERNET and WIFI_CONNECTED_HAS_NO_INTERNET statuses + * can be emitted by observeConnectivity(context) method. When it isn't called + * only WIFI_CONNECTED can by emitted by observeConnectivity(context) method. + * + * @return ReactiveNetwork object + */ + public ReactiveNetwork enableInternetCheck() { + checkInternet = true; + return this; + } + + /** + * Observes ConnectivityStatus, + * which can be WIFI_CONNECTED, MOBILE_CONNECTED or OFFLINE + * + * @param context Context of the activity or an application + * @return RxJava Observable with ConnectivityStatus + */ + public Observable observeConnectivity(final Context context) { + final IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + + return Observable.create(new Observable.OnSubscribe() { + @Override public void call(final Subscriber subscriber) { + final BroadcastReceiver receiver = new BroadcastReceiver() { + @Override public void onReceive(Context context, Intent intent) { + final ConnectivityStatus newStatus = getConnectivityStatus(context, checkInternet); + + // we need to perform check below, + // because after going off-line, onReceive() is called twice + if (newStatus != status) { + status = newStatus; + subscriber.onNext(newStatus); + } + } + }; + + context.registerReceiver(receiver, filter); + + subscriber.add(unsubscribeInUiThread(new Action0() { + @Override public void call() { + context.unregisterReceiver(receiver); + } + })); + } + }).defaultIfEmpty(ConnectivityStatus.OFFLINE); + } + + public ConnectivityStatus getConnectivityStatus(final Context context, + final boolean checkInternet) { + final String service = Context.CONNECTIVITY_SERVICE; + final ConnectivityManager manager = (ConnectivityManager) context.getSystemService(service); + final NetworkInfo networkInfo = manager.getActiveNetworkInfo(); + + if (networkInfo == null) { + return ConnectivityStatus.OFFLINE; + } + + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + if (checkInternet) { + return getWifiInternetStatus(networkInfo); + } else { + return ConnectivityStatus.WIFI_CONNECTED; + } + } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { + return ConnectivityStatus.MOBILE_CONNECTED; + } + + return ConnectivityStatus.OFFLINE; + } + + private ConnectivityStatus getWifiInternetStatus(final NetworkInfo networkInfo) { + if (networkInfo.isConnected()) { + return ConnectivityStatus.WIFI_CONNECTED_HAS_INTERNET; + } else { + return ConnectivityStatus.WIFI_CONNECTED_HAS_NO_INTERNET; + } + } + + private Subscription unsubscribeInUiThread(final Action0 unsubscribe) { + return Subscriptions.create(new Action0() { + + @Override public void call() { + if (Looper.getMainLooper() == Looper.myLooper()) { + unsubscribe.call(); + } else { + final Scheduler.Worker inner = AndroidSchedulers.mainThread().createWorker(); + inner.schedule(new Action0() { + @Override public void call() { + unsubscribe.call(); + inner.unsubscribe(); + } + }); + } + } + }); + } +} diff --git a/settings.gradle b/settings.gradle index 27565f9e0..359bd1a68 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,3 @@ -include ':app', ':SubsamplingScaleImageView' -project(':SubsamplingScaleImageView').projectDir = new File('libs/SubsamplingScaleImageView') \ No newline at end of file +include ':app', ':SubsamplingScaleImageView', ':ReactiveNetwork' +project(':SubsamplingScaleImageView').projectDir = new File('libs/SubsamplingScaleImageView') +project(':ReactiveNetwork').projectDir = new File('libs/ReactiveNetwork') \ No newline at end of file