After Android tightens its authority, how to use Telecom technology to build VoIP calling applications and improve the experience of APP users is believed to be one of the technical topics that developers are more concerned about. This paper leads people to understand how Rongyun uses Telecom to build VoIP calling applications from several aspects, including Telecom framework overview, Telecom start-up process analysis, VoIP calling application construction, and common calling scenarios processing.

1. Background and current situation

The low version of Android receives an IM voice call. By starting the Activity in the background, you can directly jump to the call interface. However, when an IM voice call is received on Android 10 and higher, the only way to alert the user is to pop up a notification bar, which is not intuitive and may cause the call to be missed, resulting in a poor user experience.

Because starting with Android 10, the system restricts the behavior of launching an Activity from the background (component). This helps minimize disruption to the user, gives the user greater control over what is displayed on their screen, and increases user experience and security. The background application starts, which must be done by “showing notifications,” notifying the user to start a new Activity with the Notification.

In this paper, Android Telecom and the use of Telecom to build VoIP calling application are introduced, and the call interface jump of IM voice calling is realized in the advanced version of Android.

II. Overview of Telecom framework

The Android Telecom framework manages audio and video calls on Android devices. These include SIM-based calls (for example, using the Telephony framework) and VoIP calls provided by the ConnectionService API implementors.

As shown in Figure 1, Telecom is responsible for reporting call status messages and sending call control messages.

Figure 1: The Telecom message processing model

Sending process of call message: After the user operates on the call interface, the InCallAdapter (IINCallAdapter server-side implementation) object will be used to notify Telecom (and finally call the CallsManager related functions). The Telecom calls the IConnectionService encapsulated interface to initiate the call management and control related RIL requests to the Modem, and the RIL converts the corresponding messages and sends them to the Modem for execution, including dialing, answering and rejecting calls, etc.

Call status update message reporting process: RIL receives a Call status change from the Modem, notifies the current Connection and Call status or properties of the change, and then processes a series of Listener callbacks. Finally, the LNCallController creates the ParcelableCall object and sends it to the DIALER application using the LLNCallService service interface call.

Telecom acts as an interactive bridge, interacting with InCallUI and Telephony [Phone process, TeleService], as shown in Figure 2:

Figure 2: Interaction flow between Telecom modules

In addition to phone process and modem communicate through socket, processes interact with each other through AIDL. The Telecom process controls the PHONE process and the INCALLUI process through ICONnectionService.aid L and IINCALLService.aidl, respectively. The phone process (com) android) phone) and Incallui process (com) android) Incallui) through IConnectionServiceAdapter. Aidl and IInCallAdapter aidl to notice The Telecom process needs to change.

III. Analysis of Telecom start-up process

/ frameworks/base/services/Java/com/android/server/SystemServer Java SystemServer process initialization complete, StartotherServices start TelecomLoaderService system service and load Telecom: /**

  • Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.

    */

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {

.

/ / start TelecomLoaderService system services, used to load Telecom t.t raceBegin (” StartTelecomLoaderService “); mSystemServiceManager.startService(TelecomLoaderService.class); t.traceEnd(); . }

Left swipe to see more →

/ frameworks/base/services/core/Java/com/android/server/telecom/TelecomLoaderService. Java

The onBootPhase function in the TelecomLoaderService class is used to tell the SystemServer what stage the system service is currently in when the system starts. After AMS(ActivityManagerService) is started, start connecting to Telecom service. / * *

  • Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
  • to run in the system-server process so once it is loaded into memory it will stay running.
  • @hide

    */

public class TelecomLoaderService extends SystemService {

private static final ComponentName SERVICE_COMPONENT = new ComponentName( "com.android.server.telecom", "com.android.server.telecom.components.TelecomService"); private static final String SERVICE_ACTION = "com.android.ITelecomService"; Override public void onBootPhase(int phase) {if (phase == Phase_Activity_Manager_Ready) {... connectToTelecom(); Synchronized () {if (mServiceConnection!) {synchronized () {if (mServiceConnection! = null) { // TODO: Is unbinding worth doing or wait for system to rebind? mContext.unbindService(mServiceConnection); mServiceConnection = null; } TelecomServiceConnection serviceConnection = new TelecomServiceConnection(); Intent intent = new Intent(SERVICE_ACTION); intent.setComponent(SERVICE_COMPONENT); int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE | Context.BIND_AUTO_CREATE; // Bind to Telecom and register the service if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) { mServiceConnection = serviceConnection; }}}}

Left swipe to see more →

/ packages/services/Telecomm/SRC/com/android/server/telecom/components/TelecomService. Java

When binding the service, the onBind interface of TelecomService is called to initialize the whole Telecom system and return the IBinder interface. / * *

  • Implementation of the ITelecom interface.

    */

public class TelecomService extends Service implements TelecomSystem.Component {

@Override
public IBinder onBind(Intent intent) {
    Log.d(this, "onBind");
    return new ITelecomLoader.Stub() {
        @Override
        public ITelecomService createTelecomService(IInternalServiceRetriever retriever) {
            InternalServiceRetrieverAdapter adapter =
                    new InternalServiceRetrieverAdapter(retriever);

// Initialize the entire Telecom system

            initializeTelecomSystem(TelecomService.this, adapter);

// Returns the IBinder interface

synchronized (getTelecomSystem().getLock()) { return getTelecomSystem().getTelecomServiceImpl().getBinder(); }}}; }

}

Left swipe to see more →

Telecom system initialization involves creating a new TelecomSystem class, which initializes all related classes for the Telecom service. / * *

  • This method is to be called by components (Activitys, Services, …) to initialize the
  • Telecom singleton. It should only be called on the main thread. As such, it is atomic
  • and needs no synchronization — it will either perform its initialization, after which
  • the {@link TelecomSystem#getInstance()} will be initialized, or some other invocation of
  • this method on the main thread will have happened strictly prior to it, and this method
  • will be a benign no-op.

    *
  • @param context

    */

static void initializeTelecomSystem(Context context,

                                InternalServiceRetrieverAdapter internalServiceRetriever) {
if (TelecomSystem.getInstance() == null) {
    NotificationChannelManager notificationChannelManager =
            new NotificationChannelManager();
    notificationChannelManager.createChannels(context);

// Create a telecomSystem object for singleton mode

TelecomSystem.setInstance( new TelecomSystem(...) ); }

}

Left swipe to see more →

/ packages/services/Telecomm/SRC/com/android/server/telecom/TelecomSystem. Java

Constructing a singleton TelecomSystem object creates the class related to the call. Such as:

· CallsManager

· CallIntentProcessor

· TelecomServiceImpl

IV. Build VoIP calling application

4.1 List declarations and permissions

Declares a service that specifies the class used to implement the ConnectionService class in your application. The Telecom subsystem requires this service to declare the BIND_TELECOM_CONNECTION_SERVICE privilege in order to bind to it. The following example shows how to declare the service in the application list: < service android: name = “com. Example. Telecom. MyConnectionService”

android:label="com.example.telecom"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
    <action android:name="android.telecom.ConnectionService" />
</intent-filter>

</service>

Left swipe to see more →

List in your application, a statement of your applications use MANAGE_OWN_CALLS permissions, as shown in the following: < USES – permission android: name = “android. Permission. MANAGE_OWN_CALLS” / >

Left swipe to see more →

4.2 Implement connection services

Your calling application must provide an implementation of the ConnectionService class with which the Telecom subsystem can bind. Public class MyConnectionService extends ConnectionService {

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    super.onCreateIncomingConnection(connectionManagerPhoneAccount, request);
    MyConnection conn = new MyConnection(getApplicationContext());
    conn.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
    conn.setCallerDisplayName("Telecom", TelecomManager.PRESENTATION_ALLOWED);
    conn.setAddress(Uri.parse("tel:" + "10086"), TelecomManager.PRESENTATION_ALLOWED);
    conn.setRinging();
    conn.setInitializing();
    conn.setActive();
    return conn;
}

@Override
public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    return super.onCreateOutgoingConnection(connectionManagerPhoneAccount, request);
}

}

Left swipe to see more →

4.3 Realizing Connection

Your application should subclass Connection to represent incoming calls in the application. Public class MyConnection extends Connection {public class MyConnection extends Connection {

The myConnection () {} /** * Telecom subsystem calls this method whenever you add a new call, and your application should display its calling screen. */ @Override public void onShowIncomingCallUi() { super.onShowIncomingCallUi(); // Here is your custom call interface}

}

Left swipe to see more →

5. Handle common call scenarios

Take a VoIP call as an example. Follow these steps:

  1. Register for a PhoneAccount (PhoneAccount is used to receive calls, create a PhoneAccount using the TelecomManager. PhoneAccount has a unique identifier called PhoneAccountHandle, and Telecom communicates with APP through the ConnectionService information provided by PhoneAccountHandle, as shown below: TelecomManager tm = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(

    new ComponentName(this.getApplicationContext(), MyConnectionService.class),
    "AppName");

    PhoneAccount phoneAccount = PhoneAccount.builder(phoneAccountHandle, “AppName”).setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED).build();

    telecomManager.registerPhoneAccount(phoneAccount);

Left swipe to see more →

  1. Use the addNewIncomingCall(phoneAccountHandle, Bundle) method to notify the Telecom subsystem when there is a new call.
  2. The Telecom subsystem binds your application’s ConnectionService implementation, Using onCreateIncomingConnection (PhoneAccountHandle, ConnectionRequest) method request says new telephone Connection a new instance of the class.
  3. The Telecom subsystem uses the onShowinComingCallui () method to tell your application that it should display its calling screen.

conclusion

For users on Android 10 and later, the only way to receive IM messages is through a pop-up notification bar, resulting in a poor user experience. Through the introduction of this article, I hope to help Android developers, so as to improve the user experience.