Outgoing Call End Classification - android

I just want to know if when an outgoing call ends, we can differentiate and know if it was due to normal hangup (normal call end), or call end due to disconnection (loss of signal, network congestion, or any reason from the carrier)

There are two main interfaces to call events depending on whether you are using the standard call app provided or are implementing your own user interface to manage calls.
If you are using the standard call service then you limited to whatever callbacks the Android telephony manager propvides:
https://developer.android.com/reference/android/telephony/TelephonyManager.html
This is a fairly limited set of events and I don't think will give you what you are looking for. It will allow you detect that the phone has gone from off hook to idle state, but not why.
If you are implementing the user interface yourself for call control, then you have access to a rusher set of events via the InCallService:
https://developer.android.com/reference/android/telecom/InCallService.html
This provides more information in callbacks but it still does not give a 'disconnect reason' for calls, AFAIK.
Note also that to use the InCallService your app must be registered as the default phone app.

Related

Android ConnectivityService - "onUnhold" not called

I'm trying to use self-managed ConnectivityService to manage calls in-app - https://developer.android.com/guide/topics/connectivity/telecom/selfManaged
It is poorly documented and there are hardly any examples on the web, however, I've managed to make it work quite well except for one scenario - getting "onUnhold" callback in one case.
So, we are in a self-managed VoIP call on my phone (A), then we receive a regular GSM call from the second phone (B), and when I answer this on phone A, I get "onHold()" callback in my Connection object where I can put my VoIP call on hold.
Then, when I end this GSM call from phone A, I got "onUnhold()" callback from where I can set my VoIP call to be active again, BUT when the call will be ended by phone B, there is no callback whatsoever, nothing in my Connection object or even in my ConnectionService.
There is even an issue in the Android tracker that describes the exact same thing and it's really well documented, with examples on GitHub and all: https://issuetracker.google.com/issues/223757078 but Google claims that this is an expected behavior.
How can I "unHold" my VoIP connection when the remote user will end the call then? I've tried to listen PhoneStateListener/TelephonyCallback, but there I get states also from my own call and I can't distinguish if the state was from my or GSM call...

Confused about Android Telecom subsystem order of events on incoming calls

In the following link:
https://developer.android.com/guide/topics/connectivity/telecom/selfManaged
I see the quote
Use the addNewIncomingCall(PhoneAccountHandle, Bundle) method to
inform the telecom subsystem about the new incoming call.
This makes no sense to me. How is my app notifying the Telecom subsystem about incoming calls? Isn't it the other way? It seems like a new call enters the device and the Telecom framework routes it to an app to handle the logic, e.g. my application. How would my app ever know about an incoming call before the Telecom system? What mechanism would notify my application of an incoming call? What service or activity would even call the addNewIncomingCall method?
Now, my intuition says I need to use a receiver to listen for an incoming call by detecting a change in the phone state. However, the following link says that is not the proper way.
https://developer.android.com/guide/topics/connectivity/telecom
That instead you should be using the inCallService and connectionService, which are services I am currently using.
Traditionally, standalone calling apps have relied on listening to the
phone state to try to determine when other calls are taking place.
This is problematic as the phone state does not take into account
other calling apps the user may have installed. Using a self-managed
ConnectionService helps you ensure that your app will interoperate not
only with native telephony calling on the device, but also other
standalone calling apps implementing this API. The Self-Managed
ConnectionService API also manages audio routing and focus for you.
I'm just not sure how they fit into the bigger picture of receiving incoming calls. All the documentation says you don't need to implement the inCallService if you don't want your own custom user interface. But I don't see how the connectionService gets a reference to the Call object otherwise.
Does anybody have a good flow chart or other graphical representation of how the Telecom subsystem functions at a high level? How the callbacks work in the framework?
Ideally I want to use the default dialer interface, dial pads, everything but be notified first of an incoming call and programmatically silently reject the call or pass it through to the default dialer.
Thanks!

Differences between InCallService and ConnectionService

I want to make a custom dialer app which will replace my default dialer app.I did some searching and I found that a dialer app can be built using either ConnectionService or InCallService. Here they have used connectionService to make a calling app, And here IncallService has been used to make the calling app.
The use cases of ConnectionService :
Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the built-in phone app. Referred to as a system managed ConnectionService.
Are a standalone calling app and don't want their calls to be integrated into the built-in phone app. Referred to as a self managed ConnectionService.
The use cases of InCallService:
This service is implemented by an app that wishes to provide functionality for managing phone calls.
So one difference is video call. Video call is possible using connectionService.Are there any other differences I am missing? And which one should I use to make a custom Dialer App?
Connection Service:- Responsible for creating a "Connection" object with required properties and abilities, like can_mute, can_hold, can_downgrade_to_voice_call, etc, according to which options are enabled or disabled in UI.
A connection object also provides methods for call manipulation, like accepting the call, declining the call, disconnecting the call with a reason, putting the call on hold, etc.
InCallService:- The responsibility of InCallService is to provide the UI for call interaction, which includes everything from notifications, call screens, call handling buttons, etc.
Android Telecom listens to the call being created and requests the connection object from ConnectionService. All the call manipulation operations are performed on this Connection Object which stays with the Telecom until it is destroyed after the call ends.
In short, InCallService allows users to interact with the call, while ConnectionService handles the call manipulation, as per user requests made from UI provided by InCallService.
Since you are concerned about making a dialer app, InCallService is the required class to be implemented. You may go for ConnectionService if you want extended control over calls.

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.

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.

Categories

Resources