I am building an app that can use WifiManager to automagically add/connect our WiFi hosting hardware, so that the user can easily get to its webinterface.
The wifiManager.enableNetwork(i.networkId, true); part works. It returns immediately and in a few seconds wifi connects. But the webinterface activity is started right away and the WebView quickly timeouts: page could not be loaded.
This is because the WiFi connection takes a few seconds. I am also unable to inform the user about failed connection attempts.
I read up on this and it seems to me that a BroadcastReceiver could "poke" my wifi-connect activity into starting the webinterface activity. A bonus would be to also visualize a failed connect.
So, my questions:
I recon i need a BroadcastReceiver for WifiManager.SUPPLICANT_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION ?
When to register and unregister it?
Can/may i just put a loop to check a statemachine (and timeout) in between, or would that be bad design and why?
I hope this can be done while staying inside my app instance .. or would that inherently result in bugs when exiting the app while wifi is trying to connect?
edit:
As for code; i use WifiManager exactly like so: How do I connect to a specific Wi-Fi network in Android programmatically?
Targeting Android 4.1.2, and am using fragments in activities to recycle view/state instances.
You should listen to WifiManager.NETWORK_STATE_CHANGED_ACTION and check on the NetworkInfo object contained in the Intent that your are connected.
When to register : it's difficult to say without seing your code, but you could probably register just before calling wifiManager.enableNetwork
Related
I am developing an android app with BLE API from android. My app needs to connect to a BLE device, and remain connected as long as it is in range and turned on. I need to read data from it, and write data to it.
I am trying to follow the MVP architecture pattern, not strictly since activities are the starting point. But anyway, I wanted to know where should I put the interaction with Bluetooth? I am searching for answers for the following questions. I have searched StackOverflow, but couldn't find what I was looking for.
Should it be in a service bounded to the UI just like in googlesample ble app ? But, I think that would break the whole mvp architecture.
Should it be a bounded service at all ? If no, what would be the best way to implement the service? In my mind, if it's not bounded to the view, and there is a callback from the background service to display something on the UI, there is a possibility of undefined behavior.
Who should initiate the Bluetooth interaction ? The application class or some activity ?
I am looking for mainly architectural guidance, and best way to go about developing this app.
Since you have the requirement that the Bluetooth connection should keep working in the background, you should have a Foreground Service somewhere running in your app process. This will make sure your app process will be kept alive, but requires an icon to be displayed in the phone/tablet's top bar.
Whether you actually put your BLE code in this service class or not doesn't matter for the functionality.
There are of course many ways to achieve good architecture but here is my approach.
My approach would be to have a singleton class that handles all your BLE scanning, connections and GATT interactions (from now on called Manager). Since some BLE operations needs an Android Context, a good way is to use the Application context as context. Either follow Static way to get 'Context' on Android? to be able to fetch that context at any time or subclass the Application class and from its onCreate call some initialization method in your Manager and pass the context. Now you can keep all BLE functionality completely separated from Android Service/Activity/Application stuff. I don't really see the point in using bounded services etc. as long as you keep everything in the same process.
To implement a scan functionality, you can have a method in your Manager that creates Scanner objects. Write the Scanner class as a wrapper to Android's BLE scanner and expose methods to start/stop scan. When you create a Scanner that method should also take an interface as argument used for callbacks (device reports and errors). This class can now be used in for example an Activity. Just make sure that the scanner gets stopped in the Activity's onStop method to avoid leakage of objects.
There are several reasons for having a wrapped custom Scanner object instead of using Android's BLE scan API directly in the Activity. First you can apply the appropriate filtering and processing of advertising packets so it handles your type of peripheral and can show high level parameters (decoded from advertising data) in your custom advertising report callback. The manager should also listen to broadcasts when Bluetooth gets started/stopped/restarted and keep track of all started Scanners so the Scanners are restarted seamlessly when Bluetooth restarts (if you want this functionality). You may also want to keep track of timestamps of all scan starts/stops so you can workaround the new restrictions in Nougat that limits it to 5 scans per 30 seconds.
Use a similar approach when you want to connect to your peripherals. You can for example let the Manager create Device objects which have methods to start/stop the connection and have a callback interface to report events. For each supported feature (for example read some remote value) you should expose a method which starts the requests and have a callback which is called when the result arrives. Then your Manager and Device class takes care of the GATT stuff (including enqueuing all your GATT requests so you only have one outstanding GATT operation at a time). Just make sure you can always abort or ignore the result when you don't want the result, for example if an Activity's onStop or onDestroy method is called.
Since you probably want to reconnect automatically in case the device gets disconnected, you should use the autoConnect flag and set it to true when establishing the connection, which assures this. Again, the Manager should keep track of all active Device objects and automatically recreate the BluetoothGatt object when Bluetooth is restarted.
To be able to display different kind of UI stuff, like for example automatically show a warning message in your Activity when Bluetooth is turned off and remove it when Bluetooth is turned on, you should be able to register Listeners to your Manager. Have a method in your Manager for registering/unregistering a listener (which is really just a Callback) object, keep track of all the listeners and when Bluetooth state change happens, call all listeners. Then in your Activity's onStart you register a listener and in onStop you unregister it. You can have a similar approach for your Device's BLE notifications, where applicable.
What's left is how you deal with different Threads. As you might know most BLE callbacks from Android's API happen on Binder threads, so you may not update the UI from them. If you otherwise in your app don't use anything other than the main thread, you can for example post all invocations of callbacks in the Manager to the main thread, or maybe move to the main thread directly when the callback from Android's BLE stack arrives (but then be aware of things like https://bugs.chromium.org/p/chromium/issues/detail?id=647673). Just make sure you never touch the same variables from different threads.
Also if you target API 23 or higher you need UI code to let the user give permission to Location to be able to start scan. I suggest you implement this in your UI code and not in the Manager, or implement some "wrapper" or helper method in the Manager to do this.
RxCentralBle provides a paradigm for use in an app. The library design clearly shows the structure of the library. In short, RxCentralBle provides reactive interfaces for the primary Bluetooth LE actions:
BluetoothDetector - detect phone Bluetooth State
Scanner - scan for peripherals
ConnectionManager - connect to a peripheral
PeripheralManager - queue operations to communicate with a peripheral
It's recommended to subscribe to these interfaces on a background thread and ensure resources and subscriptions live at the application scope i.e. member variables of your Application class. As long as your Application is running, all Bluetooth LE resources will remain alive and active.
Check out RxCentralBle's Wiki and sample app to learn more.
im currently writing an android app, which should keep track of other devices in the same wifi network using JmDNS.
The discovery process works correctly, but i don't know how to keep track of other devices especially noticing their removing.
As mentioned in
JmDNS device removal detection it seems like i have to implement this callback myself but I dont have any clue how to do this. It seems like the JmDNS Api doesn't provide any method to publish service messages myself.
My ideas so far:
Use the discovered socket connection to keep track of changes
Use JmDNS.requestServiceInfo() from time to time to check if the service is still available
Un-/Register services + listeners so they can find each other again
Does anyone know another way to solve this issue or could tell me how to trigger the serviceRemoved() callback?
PS: before taking this approach I tried Androids-NSD API, which seems to be quite unstable
So here are some things i figured out while experimenting:
The DNS-cache is set to one hour, which means that listeners won't remove a service as long as that counter didn't finish.
The mistake i made was unregistering my service after the wifi was switched off. Services send broadcast message that they aren't available anymore. This message can't be sent if the wifi connection was shutdown.
So instead of calling JmDNS.unregisterAllServices() after the wifi connection I have to call it when it's available. This leads to the onServiceRemoved() callback beeing fired in the listener
For my app, I would like to have a service running at all times that the app is loaded that will be checking the availability of a network connection, and as soon as it realizes that a network connection is not available, send a message to the loaded activity so that I can replace the content view of that activity with one that simply states "Network Connection is not available". Then when the network connection comes back, have the activity receive another message so it can switch the content view back. I've looked through several posts on services, and would just like to inquire as the best way to go about this. Any tutorials or simple sample code would be awesome too!
Using a Service for that is not really the best solution. Better is using a BroadcastReceiver. You can add one programmatically as shown here, or in the manifest like here.
I have a really annoying problem.
What happens is I have an application which is using native sockets to send data over TCP.
When I first launch my application and send data over the sockets, nothing gets through. However if I then quit the process and restart it and then send again, it works. Same thing if I open the browser or something before starting my app for the first time after sleep mode.
How do I 'force' 3G to go out of sleep mode before I make the call to the native code?
EDIT: I have already tried with PowerManager.
Try calling startUsingNetworkFeature (int networkType, String feature) On a ConnectivityManager and wait for it to be available before you bind your sockets ect......
Android Documentation
I'd give the ConnectivityManager API requestRouteToHost(int networkType, int hostAddress) a try.
OS: Android
Given: User has stated that they wish to remain connected to app's server to receive updates, etc.
Goal: To ensure that users are connected to app's server even when app is in background state.
Question: One problem has been occasional disconnects from the network. If a user loses data network connectivity (loss of 2G, 3G, WiFi) and then later regains connectivity, our app is left without a connection. I am currently trying to make use of PhoneStateListener's in order to detect various network changes and thereby restart connectivity with the server when appropriate. On my Nexus One (2.1), I find that onSignalStrengthsChanged and onDataConnectionStateChanged aren't called except when the listeners are originally registered, but not afterwards. The listeners are registered inside of a Service so they are continuously listening as long as the Service is alive (which we can assume to be 'forever' for purposes of this question). Has anyone else had any issues with listening to the state of the Data Connection?
onServiceStateChanged seems to be the most reliable so far, but I wanted to know if people have had success with the other listeners as well.
I guess you'll have to send keepalive messages at regular intervals to check whether the connection is still there. If not, reestablish it. There is a smorgasbord of reasons why your connection might drop, and you won't be able to check all of those client side.
Might consider using google's cloud service for what you're doing though, since they already keep an connection open for that. That way your user's phones won't have the overhead of keeping yet another connection around (which can be quite expensive)
Since StackOverflow doesn't allow me to close the question otherwise, I will provide the answer to why my PhoneStateListeners were not working:
I discovered that my problem was simply that I wasn't registering my listeners in a bitwise manner, but rather successively (i.e.
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
telephonyManager.listen(listener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
.
.
.
instead of (the correct):
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE..............);)
I will close this question and perhaps later open a different question asking for design suggestion on maintaining 'always alive' connections to a server on Android. Thanks.
As far as i know listeners could not be called when app is in background. You should try use services not activity.
And also remember to retrieve TelephonyManager in proper way
TelephonyManager mTelephonyMgr = (TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE);
I would think you would use the ConnectivityManager for this.
Class that answers queries about the state of network connectivity. It also notifies applications when network connectivity changes. Get an instance of this class by calling Context.getSystemService(Context.CONNECTIVITY_SERVICE).
http://developer.android.com/reference/android/net/ConnectivityManager.html
per the docs, it monitors network connectivity and sends broadcast intents on change to applications.