Giter Site home page Giter Site logo

pwittchen / reactivewifi Goto Github PK

View Code? Open in Web Editor NEW
189.0 7.0 39.0 332 KB

Android library listening available WiFi Access Points and related information with RxJava Observables

License: Apache License 2.0

Java 81.17% Kotlin 18.83%
android wifi scanner access-point rxjava rxandroid rxjava2 rxandroid2

reactivewifi's Introduction

ReactiveWiFi Android Arsenal

Android library listening available WiFi Access Points and related information with RxJava Observables.

Current Branch Branch Artifact Id Build Status Maven Central
RxJava1.x reactivewifi Build Status for RxJava1.x Maven Central
☑️ RxJava2.x reactivewifi-rx2 Build Status for RxJava2.x Maven Central

This library is one of the successors of the NetworkEvents library. Its functionality was extracted from ReactiveNetwork project to make it more specialized and reduce number of required permissions required to perform specific task.

If you are searching library for observing network or Internet connectivity check ReactiveNetwork project.

JavaDoc is available at: http://pwittchen.github.io/ReactiveWiFi/RxJava2.x

Contents

Usage

Library has the following RxJava Observables available in the public API:

Observable<List<ScanResult>> observeWifiAccessPoints(final Context context)
Observable<Integer> observeWifiSignalLevel(final Context context, final int numLevels)
Observable<WifiSignalLevel> observeWifiSignalLevel(final Context context)
Observable<SupplicantState> observeSupplicantState(final Context context)
Observable<WifiInfo> observeWifiAccessPointChanges(final Context context)
Observable<WifiState> observeWifiStateChange(final Context context)

Please note: Due to memory leak in WifiManager reported in issue 43945 in Android issue tracker it's recommended to use Application Context instead of Activity Context.

Observing WiFi Access Points

Please note: If you want to observe WiFi access points on Android M (6.0) or higher, you need to request runtime permission for ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION. After that, location services have to be enabled. See sample app in app directory to check how it's done. User needs to enable Location manually. You can suggest him or her to do it via AccessRequester class from this library as follows:

if (!AccessRequester.isLocationEnabled(this)) {
  AccessRequester.requestLocationAccess(this);
} else {
  // observe WiFi Access Points
}

If you need more customization (e.g. custom title and message of the dialog window or custom listener), check public API of the AccessRequester class.

We can observe WiFi Access Points with observeWifiAccessPoints(context) method. Subscriber will be called everytime, when strength of the WiFi Access Points signal changes (it usually happens when user is moving around with a mobile device). We can do it in the following way:

ReactiveWifi.observeWifiAccessPoints(context)
    .subscribeOn(Schedulers.io())
    ... // anything else what you can do with RxJava
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(scanResults -> {
      // do something with ScanResults
    });

Hint: If you want to operate on a single ScanResult instead of List<ScanResult> in a subscribe(...) method, consider using flatMap(...) and Observable.from(...) operators from RxJava for transforming the stream.

Observing WiFi signal level

We can observe WiFi signal level with observeWifiSignalLevel(context, numLevels) method. Subscriber will be called everytime, when signal level of the connected WiFi changes (it usually happens when user is moving around with a mobile device). We can do it in the following way:

ReactiveWifi.observeWifiSignalLevel(context, numLevels)
    .subscribeOn(Schedulers.io())
    ... // anything else what you can do with RxJava
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(level -> {
      // do something with level
    });

We can also observe WiFi signal level with observeWifiSignalLevel(final Context context) method, which has predefined num levels value, which is equal to 4 and returns Observable<WifiSignalLevel>. WifiSignalLevel is an enum, which contains information about current signal level. We can do it as follows:

ReactiveWifi.observeWifiSignalLevel(context)
    .subscribeOn(Schedulers.io())
    ... // anything else what you can do with RxJava
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(level -> {
      // do something with level
    });

WifiSignalLevel has the following values:

public enum WifiSignalLevel {
  NO_SIGNAL(0, "no signal"),
  POOR(1, "poor"),
  FAIR(2, "fair"),
  GOOD(3, "good"),
  EXCELLENT(4, "excellent");
  ...
}

Observing WiFi information changes

We can observe WiFi network information changes with observeWifiAccessPointChanges(context) method. Subscriber will be called every time the WiFi network the device is connected to has changed. We can do it in the following way:

ReactiveWifi.observeWifiAccessPointChanges(context)
    .subscribeOn(Schedulers.io())
    ... // anything else what you can do with RxJava
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(wifiInfo -> {
      // do something with wifiInfo
    });;

Observing WPA Supplicant state changes

We can observe changes in the WPA Supplicant state with observeSupplicantState(context) method. Subscriber will be called every time the WPA Supplicant will change its state, getting information at a lower level than usually available. We can do it in the following way:

ReactiveWifi.observeSupplicantState(context)
    .subscribeOn(Schedulers.io())
    ... // anything else what you can do with RxJava
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(state -> {
      // do something with state
    });

Observing WiFi state changes

We can observe wifi state change with observeWifiStateChange(context) method. Subscriber will be called every time whenever the wifi state change such like enabling,disabling,enabled and disabled. We can do it in the following way:

ReactiveWifi.observeWifiStateChange(context)
    .subscribeOn(Schedulers.io())
    ... // anything else what you can do with RxJava
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(state -> {
      // do something with level
    });

Examples

Exemplary application is located in app directory of this repository.

If you want to use this library with Kotlin, check app-kotlin directory.

Download

<dependency>
    <groupId>com.github.pwittchen</groupId>
    <artifactId>reactivewifi-rx2</artifactId>
    <version>0.3.0</version>
</dependency>

or through Gradle:

dependencies {
  implementation 'com.github.pwittchen:reactivewifi-rx2:0.3.0'
}

Code style

Code style used in the project is called SquareAndroid from Java Code Styles repository by Square available at: https://github.com/square/java-code-styles.

Static code analysis

Static code analysis runs Checkstyle, FindBugs, PMD and Lint. It can be executed with command:

./gradlew check

Reports from analysis are generated in library/build/reports/ directory.

License

Copyright 2016 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.

reactivewifi's People

Contributors

agatti avatar bhavdip avatar bhavdipcreolestudios avatar chintanrathod avatar dependabot-preview[bot] avatar pwittchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactivewifi's Issues

Investigate continuous monitoring of RSSI (ScanResult.level) in dBm

Investigate continuous monitoring of ScanResult.level (RSSI) in dBm. Not only when WiFi signal strength changes (what is indicated by system broadcast), but all the time within a given interval.

Draft of proposed API (it may change):

Observable<Integer> observeRssiOfConnectedAp();
Observable<Integer> observeRssiOfConnectedAp(int observingIntervalInMs);
Observable<Integer> observeRssi(String accessPoint);
Observable<Integer> observeRssi(String accessPoint, int observingIntervalInMs);

References:
https://developer.android.com/reference/android/net/wifi/ScanResult.html

Too much callbacks when observing "observeWifiAccessPoints"

I'm using ReactiveWifiLocal.observeWifiAccessPoints(context) everything works well except that I'm receiving too much events, and it is causing high cpu load, lags and battery drain.
I can handle it partially by using .throttleFirst(SAMPLING_TIME, TimeUnit.SECONDS) but anyway the library it-selves receives callbacks in BroadcastReceiver

I suggest to do something like

 public static Observable<List<ScanResult>> observeWifiAccessPoints(final Context context,final int scanInterval) {
     final WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
     wifiManager.startScan(); // without starting scan, we may never receive any scan results

    final IntentFilter filter = new IntentFilter();
    filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
    filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

    return Observable.create(new Observable.OnSubscribe<List<ScanResult>>() {
        @Override
        public void call(final Subscriber<? super List<ScanResult>> subscriber) {
            final BroadcastReceiver receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {

                    AndroidSchedulers.mainThread().createWorker().schedule(new Action0() {
                        @Override
                        public void call() {
                            wifiManager.startScan(); // we need to start scan again to get fresh results ASAP
                        }
                    }, scanInterval, TimeUnit.SECONDS);

                    subscriber.onNext(wifiManager.getScanResults());
                }
            };

            context.registerReceiver(receiver, filter);

            subscriber.add(unsubscribeInUiThread(new Action0() {
                @Override
                public void call() {
                    context.unregisterReceiver(receiver);
                }
            }));
        }
    });
}

This is how often I get updates:

10-30 13:31:29.051 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.118 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.159 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.199 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.304 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.358 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.396 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.426 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.465 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.499 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.538 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.580 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items
10-30 13:31:29.626 28695-28695/br.com.oitchau D/WiFiListener: mark as available 8 items

WiFi Scan return result as zero, It's not working in Marshmallow Android 6.0.1

I try the demo example. I run it in MarshMallow Android version 6.0.1 it asked for the location permission that would adequate. But after allowing the permission granted still the list return result size is 0. After debugging found that inside this method observeWifiAccessPoints the start scan work perfect but wifiManager.getScanResults() return the scan results in zero.

final BroadcastReceiver receiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
            wifiManager.startScan(); // we need to start scan again to get fresh results ASAP
            subscriber.onNext(wifiManager.getScanResults());
          }
        };

After spedning lots of time found that it's bug after android version 6. The WifiManager#getScanResults() returns an empty array list if GPS is turned off. Only permission granted would not work.

So I post this issue to inform to other people who using this lib and suppose to not get the list then they need to turn on the GPS to getting start to scan the wifi. Only Allowing location permission would not work.

Thanks

New release question

Hi,
Any plans to make a new release on Gradle repo? I see there was a lot of changes in RxJava since 2018.

Anyway, thanks for great lib!

Android 8+ scan throttle

After version 8.0 Android started apply limitations to the frequency of scans using. The new limitations are;

Android 8.0 and Android 8.1:

Each background app can scan one time in a 30-minute period.

Android 9:

Each foreground app can scan four times in a 2-minute period. This allows for a burst of scans in a short time.

All background apps combined can scan one time in a 30-minute period.

https://developer.android.com/guide/topics/connectivity/wifi-scan

According to these the sample application is failed to update the values after 4 scans.

Error receiving broadcast Intent { act=android.net.wifi.supplicant.STATE_CHANGE flg=0x24000010 (has extras) } in com.github.pwittchen.reactivewifi.ReactiveWifi$4$1@b745bb

I'm using Android API level 22, everything works fine but occasionally the app crashes. I've added stacktrace:

05-10 09:07:34.009 F/MyExceptionHandler( 4098): Error receiving broadcast Intent { act=android.net.wifi.supplicant.STATE_CHANGE flg=0x24000010 (has extras) } in com.github.pwittchen.reactivewifi.ReactiveWifi$4$1@b745bb 05-10 09:07:34.009 F/MyExceptionHandler( 4098): java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.supplicant.STATE_CHANGE flg=0x24000010 (has extras) } in com.github.pwittchen.reactivewifi.ReactiveWifi$4$1@b745bb 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:915) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at android.os.Handler.handleCallback(Handler.java:815) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at android.os.Handler.dispatchMessage(Handler.java:104) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at android.os.Looper.loop(Looper.java:194) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at android.app.ActivityThread.main(ActivityThread.java:5637) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at java.lang.reflect.Method.invoke(Native Method) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at java.lang.reflect.Method.invoke(Method.java:372) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): Caused by: java.lang.IllegalStateException: more items arrived than were requested 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at rx.internal.producers.ProducerArbiter.produced(ProducerArbiter.java:98) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at rx.internal.operators.OperatorSwitchIfEmpty$ParentSubscriber.onNext(OperatorSwitchIfEmpty.java:91) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at com.github.pwittchen.reactivewifi.ReactiveWifi$4$1.onReceive(ReactiveWifi.java:164) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:905) 05-10 09:07:34.009 F/MyExceptionHandler( 4098): ... 8 more 05-10 09:07:34.011 I/MyExceptionHandler( 4098): tv.isern.alexiafe.activity.LoginPacientActivity-java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.supplicant.STATE_CHANGE flg=0x24000010 (has extras) } in com.github.pwittchen.reactivewifi.ReactiveWifi$4$1@b745bb 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:915) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at android.os.Handler.handleCallback(Handler.java:815) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at android.os.Handler.dispatchMessage(Handler.java:104) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at android.os.Looper.loop(Looper.java:194) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at android.app.ActivityThread.main(ActivityThread.java:5637) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at java.lang.reflect.Method.invoke(Native Method) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at java.lang.reflect.Method.invoke(Method.java:372) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): Caused by: java.lang.IllegalStateException: more items arrived than were requested 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at rx.internal.producers.ProducerArbiter.produced(ProducerArbiter.java:98) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at rx.internal.operators.OperatorSwitchIfEmpty$ParentSubscriber.onNext(OperatorSwitchIfEmpty.java:91) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at com.github.pwittchen.reactivewifi.ReactiveWifi$4$1.onReceive(ReactiveWifi.java:164) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:905) 05-10 09:07:34.011 I/MyExceptionHandler( 4098): ... 8 more

Failed to resolve

All other dependencies are resolved correctly.

allprojects {
    repositories {
        jcenter()
    }
}

Error:Failed to resolve: com.github.pwittchen:reactivewifi:0.1.1

Release 0.3.0

Initial release notes:

  • fixed bug: Error receiving broadcast Intent... #28
  • migrated library to RxJava2.x as a separate artifact
  • bumped Gradle to v. 3.0
  • updated project dependencies
  • added Retrolambda to sample java app

Things to do:

  • RxJava1.x branch
    • update JavaDoc on gh-pages
    • bump library version to 0.3.0
    • upload Archives to Maven Central Repository
    • close and release artifact on Nexus
    • update CHANGELOG.md after Maven Sync
    • update download section in README.md after Maven Sync
    • create new GitHub release
  • RxJava2.x branch
    • update JavaDoc on gh-pages
    • bump library version to 0.3.0
    • upload Archives to Maven Central Repository
    • close and release artifact on Nexus
    • update CHANGELOG.md after Maven Sync
    • update download section in README.md after Maven Sync
    • create new GitHub release

Release 0.1.0

Initial release notes:

  • added Observable<SupplicantState> observeSupplicantState(context) method, which observes the current WPA supplicant state.
  • added Observable<WifiInfo> observeWifiAccessPointChanges(context) method, which observes the WiFi network the device is connected to.

Things to do:

  • bump library version to 0.1.0 ➡️ done in 9050eb4
  • upload Archives to Maven Central Repository
  • close and release artifact on Nexus
  • update gh-pages
  • update CHANGELOG.md after Maven Sync
  • update download section in README.md after Maven Sync
  • create new GitHub release

Release 0.1.1

Initial release notes:

  • bumped RxJava to v. 1.1.8
  • bumped RxAndroid to v. 1.2.1
  • bumped Gradle Build Tools to 2.1.2

Things to do:

  • bump library version to 0.1.1
  • upload Archives to Maven Central Repository
  • close and release artifact on Nexus
  • update CHANGELOG.md after Maven Sync
  • update download section in README.md after Maven Sync
  • create new GitHub release

Release 0.2.0

Initial release notes:

  • added WifiState enum
  • added Observable<WifiState> observeWifiStateChange(context) to ReactiveWifi class
  • updated Gradle and Travis CI config
  • updated Gradle Wrapper version
  • bumped target SDK version to 25 and build tools version to 25.0.1
  • bumped RxJava to v. 1.2.6
  • made methods, which create Observables in ReactiveWifi class static
  • made the constructor of ReactiveWifi class private
  • added permission annotations
  • added AccessRequester class responsible for checking if Location Services are enabled and redirecting the user to Location Settings

Things to do:

  • bump library version to 0.2.0
  • upload Archives to Maven Central Repository
  • close and release artifact on Nexus
  • update JavaDoc on gh-pages
  • update CHANGELOG.md after Maven Sync
  • update download section in README.md after Maven Sync
  • create new GitHub release

release v. 0.0.1

Initial release notes:

First release of the library.

Things to do:

  • upload Archives to Maven Central Repository
  • close and release artifact on Nexus
  • update gh-pages
  • create CHANGELOG.md after Maven Sync
  • update download section in README.md after Maven Sync
  • create new GitHub release

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.