Android: Design Pattern for asynchronous events (intents) handling - android

I'm developing an app which interacts with phone's WiFi, Bluetooth, Mobile Network.
The app is mainly a Service, and the GUI doesn't play a central role.
The core of the app, and the principal method of the service class is a single method which receives all intents that the app needs to receive:
public void handleIntent(Intent intent){
It then extracts the intent's action and calls a specific handler method for the corresponding intent's action, for instance when receiving a SCREEN_ON, it would call
private void handleScreenOn(){
Problem is that some tasks on the phone take some time, so that some other events may occur in the middle of the processing of the task, that should change processing.
For instance, turning ON the Wifi would take a couple of seconds, sending several intents WIFI_STATE_CHANGED_ACTION before it's actually completed. In the middle of the WiFi being enabled, the user can turn off the screen so that a SCREEN_OFF intent would be received.
Now say that my app's goal is to turn off WiFi when screen gets turned Off. There is a situation where a problem occurs:
Initial situation: Screen is On, WiFi is Off
User toggles WiFi setting to enable it. Wifi starts getting enabled
User almost immediately turns screen Off
The app receives the SCREEN_OFF intent but since WiFi is not enabled yet, then it believes that there is no need to disable it
Wifi enabling gets finished, and Wifi stays enabled despite the screen being off.
How to solve it?
Currently, in step 5, when Wifi gets finally enabled, I would test whether screen is off or not to turn off wifi again.
This solution requires many if / else handling all possible cases.
I'm sure there must be some cleaner way of doing it, handling a stack of intents, or something like this...
Anyone with some good design patter or good advice on how to do it cleanly?

Consider sending an "action completed" event whenever you (asynchronously) complete the reaction to some event. Now you can add some logic in handleIntent() to achieve a consistent state. The logic is at a central position in your components and code duplication is avoided.
Alternatively you can try to serialize your events: i.e. when an event occurs which may invalidate the outcome of some not yet finished action (you need to manage a list of not completed action, completion can be detected as outlined above) postpone its handling until all those actions are completed. To decide which events may depend on other events a simple, static lookup-table should suffice.

Another approach would be to maintain the state of the entities (either all of them, or just those that are asynchronous) being managed. For those that are asynchronous, the state should not be binary (ON|OFF), but rather have at least 3 or 4 states: ON, TURNING_ON, OFF, TURNING_OFF. Then in your example step 4, when you receive the SCREEN_OFF, check for the WIFI states ON or TURNING_ON, to determine if you have to turn it off.

Related

Why can we pair with the BLE device, without displaying system Dialog, by using BroadcastReceiver?

I'm using RxAndroidBle library to scan and connect with BLE devices. What I also need is to pair with this found device, without displaying system dialog about the key pairing. The bonding mechanism is JustWorks.
I've already achieved that by creating BroadcastReceiver, following the gist I posted below(credits to #dglozano).
Code gist:
https://gist.github.com/dglozano/9b0ce38a558eeca16137909bd368698c
It actually works pretty well but I would like to understand why when I'm simply using rxBleDevice.bluetoothDevice.createBond() it displays the Dialog but when I handle it by my own BroadcastReceiver then, it doesn't. Is this someway unregistering normal BroadcastReceiver that would handle device BOND_STATE? Why my BroadcastReceiver takes main control of that? I'm interested in - what happens inside when I'm registering my own receiver.
Okay, I figured it out.
My first impression that this BroadcastReceiver handles this system Dialog was wrong. We use this Receiver only to double-check BOUND_STATE. It has nothing to do with pairing dialog, this assumption was a mistake.
So the first important fact is that only a createBond() method is necessary to pair. The rest is just about establishing it.
The most important fact is that this is "Just works" pairing method. There we can read about BLE security and about "Just works". As you can read here:
In this method, the TK is set to 0.
TK is a Temporary Key.
At this moment, let go back for the moment to our Android createBond() method. In the documentation we can read:
Android system services will handle the necessary user interactions to confirm and complete the bonding process.
But if it handles user interactions why it doesn't display a dialog? We find the answer when we combine those two things together. When Temporary Key value is set to 0, then displaying Pairing key dialog isn't necessary for Android handler.
There are small changes between Bluetooth 4.0/4.1 and Bluetooth 4.2 but it shouldn't have an impact on this behavior. You can read more about it here.
TL:DR Using "Just works" pairing method means that Temporary Key value is set to 0 which means we don't need it during the pairing process. createBound() method handles only necessary user interactions so when we don't need pairing key, we don't need to interact with a user about it. That's why Dialog isn't being displayed - because it isn't necessary.

Android app architecture with BLE

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.

What is the most efficient way to check a user is online (Messaging Application)

We are trying to develop a Messaging Application(Mobile) like Viber. We are now woking on User Status (The user is online or not). We have tested Viber yesterday and understand that if a user close the application or if a user goes out of the Network, rest of other users got it immediately. I mean rest of the users got that the User was Online 'a moment ago'
I know that if the user change his Status, or if a user close the application, an event can fire a request to the server and inform that the user is not online now. And the Server then notify everyone(related users) that message by using Push Method. But if the user goes Out of Network(Disable wifi/cellular), how everyone (related users) get Notified?
What is the efficient way? Any reference link?
Thanks..
You're right about how these protocols work. If a user shuts off, it immediately broadcasts to peers that they're no longer on the network.
But like you mentioned, this doesn't work when someone crashes or loses signal. Generally you want to keep polling the user to make sure that they're still there. There's an efficiency cost, and the amount of time you wait between each poll is something you should determine. There's a tradeoff between immediately being informed vs. polling too frequently and sucking up resources.
Update:
I might be wrong, but I think that viber/what is probably polling, and since it's polling frequently it looks like it's immediate.
I don't know how it would otherwise be possible to inform the programs if it crashes, since crashing means it can't functionally send any kind of signal. So it must be polling so frequently that it seems immediate.
change the colour of your online/ offline button in these methods appdelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
this will work for ios

How do I know who ended the call in Android - User or Remote User?

I want to specifically know who ended the call. I have setup a broadcast receiver for
"android.intent.action.PHONE_STATE"
When I detect a transition from Off hook to idle, I know the call has ended. But how do I know who ended the call?
Thanks a ton!
I'm afraid there's presently no way to determine if the user pressed "end call" or if the other end (or ends, in a group call) terminated. The only workaround I can suggest is monitoring the other states to observe if the phone state ringing was encountered. In such a case, you could assume the user is making the phone call as opposed to receiving it.
Bear in mind that there are other problems related to PHONE_STATE, such as handling multiple calls simultaneously.
In retrospect, I'm not entirely sure what you mean with "who". As for other apps ending the call: there is no official API to end phone calls; only through reflection can an app invoke the TelephonyService's endCall() function. Here, too, it is not possible to determine if the call was terminated through user interaction or not.

Suppress Android incoming call Activity from appearing

How are things now
This has been discussed in many questions but neither one offers a good solution. Things look simple, after having a BroadcastReceiver is really easy to intercept and block a call. The main issue that appears is the default Android incoming call screen. You know, the one with sliders for answer/end call. Because i have some rules to block the call, there is a small delay before the call gets hangup. In all this time, the Incoming call screen is active.
How I want things to be
I want the user to not get notified by this call blocking, as in my application I have a clear Log of all blocks done. So, the main thing remains: how do I prevent the Incoming call screen from starting?
It is not possible to completely block the calls but you can achieve this by listening the call and then disconnecting it. It's behaviour may be different in different devices. It may show negligible flicker over some device but that's the only solution.
Here is the approach how you can do that:
Android: Taking complete control of phone(kiosk mode), is it possible? How?
You can use BroadcastReceiver but for alomost blocking experience you need to use Service.

Categories

Resources