Android default dialer replacement (part II)

Miguel Barrios
Making Tuenti
Published in
4 min readApr 18, 2018

After implementing a default dialer replacement app in the first part of this series we should have an app that can be selected by the user as the default phone app, but if we select it, we might lose all our calls, because we didn’t implement a UI for it. In this post we will create a new Activity that listens to all the changes in the InCallService and renders the state of the call, the phone number of the other call party and a couple of buttons to answer and reject/cancel a call.

InCallService callbacks

Remember in part I we implemented an InCallService, but it was an empty implementation, the bare minimum to be able to qualify as dialer replacement.

This service is going to receive the callbacks about the state of the current call, so let’s implement the methods we need to.

We implemented methods to know when a call starts and when it ends. When the call starts we can start our Activity to render the UI. In this method we receive a Call instance which contains all the info relevant to the current call. We want to listen to changes in the state of this call, so we can register a Call.Callback and send updates to the Activity whenever the state changes. In the onCallRemoved method we can just unregister the call callback.

Send call updates

In order to send call updates to the Activity we chose Rx, since it seems very natural to have a stream of Call objects generated from this InCallService callbacks and then any body can subscribe to that stream and react to it.

We created a CallManager object that will receive every Call update and will transform them into a stream of Calls.

  • It’s an object so we can easily share the instance and call it both from the Service and from the Activity.
  • We’ll use a BehaviorSubject to create the stream of calls so anybody can subscribe at any given moment and always receive the current call state.
  • We are also mapping the Call instance to a GsmCall instance. GsmCall is a model with only the information we’re going to render later so we simplify a bit the info received by the Activity later.

Here are the GsmCall data class and the corresponding mapper.

Now we will feed the stream from the InCallService.

We’ll send updates from onCallAdded, onCallRemoved and onStateChanged in the Call.Callback. That way we won’t lose any update potentially useful for our UI.

Call screen

And now that we finished with the plumbing, we can start rendering stuff. You can have a look at the call Activity layout XML in the repo, here’s just the layout preview so you get the idea and see the TextViews and Buttons we’re going to deal with.

Call screen preview

And the Activity itself.

We subscribe to call updates in the onResume function and unsubscribe in onPause like good Rx citizens. And in the updateView function we just update the TextViews with the state of the call and the phone number of the other party.

Finally, we want to be able to answer and reject calls from our UI, so let’s go back to CallManager object and create a couple of new methods.

We need to call the corresponding accept/reject functions in a Call instance, so we’re going to store one inside CallManager and update it every time updateCall is invoked. Since there might be no call at all at some moments, currentCall will be nullable.

Check that we also added a couple of public functions, acceptCall and cancelCall. In the cancelCall function we check the state of the current call and call Call.rejectCall only if the state is “ringing”, and Call.disconnectCall otherwise. In the answer method we need to indicate the videoState value, since in this case we’re not supporting video calls (for now), we just use the same videoState currentCall has. Now we can call these two functions from CallActivity when we click on the answer and cancel buttons respectively.

And that’s it, thanks for reading. If you have a look at the GitHub repo you will find some other details like a small trick to update the duration TextView using Rx, or how to make the call screen go full-screen with Themes and hiding the bottom system navigation bar.

--

--