Build a Video Calling App with Call Trigger in Android (Kotlin) using Firebase and VideoSDK
In this tutorial, we will be building an Android video calling app using the Telecom framework, VideoSDK, and Firebase. The app will allow users to make video calls with other users who have installed the app on their devices. We will also implement a notification system that notifies users when they receive incoming calls. Here's what we'll cover in this tutorial: 1. Setting up the Android project and adding required dependencies 2. Implementing the IncomingCallScreen to handle incoming video calls 3. Implementing the OutgoingCallScreen to initiate video calls 4. Implementing the MeetingActivity to manage ongoing video calls 5. Integrating Firebase Cloud Messaging for push notifications 6. Testing the app on multiple devices Before we begin, make sure you have Android Studio installed on your system and create a new project with an Empty Activity template. 1. Setting up the Android project and adding required dependencies First, let's add the necessary dependencies to our build.gradle files: In `app/build.gradle`, add the following dependencies: ```groovy dependencies { implementation 'com.google.android.gms:play-services-auth:19.0.0' implementation 'com.google.firebase:firebase-messaging:22.0.0' implementation 'com.videosdk.cloud:reactnative-plugin:4.3.0' } ``` In `project/build.gradle`, add the following dependencies under `allprojects -> repositories` section: ```groovy repositories { google() mavenCentral() jcenter() maven { url 'https://jitpack.io' } } ``` Now, let's create a new class named `IncomingCallScreen` that will handle incoming video calls: ```java public class IncomingCallScreen extends AppCompatActivity { private static final String TAG = "IncomingCallScreen"; private TextView tvName; private ImageButton ibAccept, ibReject; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_incoming_call_screen); initUI(); // Get the caller's name from intent extras String callerName = getIntent().getStringExtra("name"); if (TextUtils.isEmpty(callerName)) { callerName = "Unknown"; } tvName.setText(callerName); } private void initUI() { tvName = findViewById(R.id.tvName); ibAccept = findViewById(R.id.ibAccept); ibReject = findViewById(R.id.ibReject); ibAccept.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Accept the incoming call and start a new MeetingActivity Intent intent = new Intent(IncomingCallScreen.this, MeetingActivity.class); intent.putExtra("name", tvName.getText().toString()); startActivity(intent); finish(); } }); ibReject.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Reject the incoming call and end it on both sides TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); if (telecomManager != null) { telecomManager.endCall(); } finish(); } }); } } ``` Next, let's create a new class named `OutgoingCallScreen` that will handle outgoing video calls: ```java public class OutgoingCallScreen extends AppCompatActivity { private static final String TAG = "OutgoingCallScreen"; private TextView tvName; private ImageButton ibHangUp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_outgoing_call_screen); initUI(); // Get the callee's name from intent extras String calleeName = getIntent().getStringExtra("name"); if (TextUtils.isEmpty(calleeName)) { calleeName = "Unknown"; } tvName.setText(calleeName); } private void initUI() { tvName = findViewById(R.id.tvName); ibHangUp = findViewById(R.id.ibHangUp); ibHangUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // End the ongoing call and return to MainActivity TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); if (telecomManager != null) { telecomManager.endCall(); } finish(); } }); } } ``` Now, let's create a new class named `MeetingActivity` that will manage ongoing video calls: ```java public class MeetingActivity extends AppCompatActivity { private static final String TAG = "MeetingActivity"; private TextView tvName; private ImageButton ibHangUp, ibWebcam, ibMic; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_meeting); initUI(); // Get the meeting ID and participant name from intent extras String meetingId = getIntent().getStringExtra("id"); String participantName = getIntent().getStringExtra("name"); // Initialize VideoSDK with your App's credentials VideoSDK.init(this, "YOUR_APP_ID", "YOUR_API_KEY", "YOUR_API_SECRET"); // Start a new video meeting with the given parameters VideoSDK.startMeeting(meetingId, participantName, true, true, null, null); } private void initUI() { tvName = findViewById(R.id.tvName); ibHangUp = findViewById(R.id.ibHangUp); ibWebcam = findViewById(R.id.ibWebcam); ibMic = findViewById(R.id.ibMic); ibHangUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // End the ongoing video meeting and return to MainActivity VideoSDK.leaveMeeting(); finish(); } }); ibWebcam.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Toggle the local participant's webcam visibility VideoSDK.toggleWebcam(); } }); ibMic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Toggle the local participant's microphone mute/unmute state VideoSDK.toggleMic(); } }); } } ``` Finally, let's create a new class named `MainActivity` that will handle incoming and outgoing video calls: ```java public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize Firebase Cloud Messaging and register for push notifications FirebaseMessaging.getInstance().subscribeToTopic("all"); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if (TelecomManager.ACTION_INCOMING_CALL.equals(intent.getAction())) { // Handle incoming video call by starting IncomingCallScreen activity Intent i = new Intent(this, IncomingCallScreen.class); i.putExtra("name", intent.getStringExtra(TelecomManager.EXTRA_Incoming_CALL_PERFORMER_NAME)); startActivity(i); } else if (intent.hasExtra("id") && intent.hasExtra("name")) { // Handle outgoing video call by starting OutgoingCallScreen activity Intent i = new Intent(this, OutgoingCallScreen.class); i.putExtra("name", intent.getStringExtra("name")); startActivity(i); } } } ``` Now that we have implemented the necessary classes and XML layout files, let's move on to integrating Firebase Cloud Messaging for push notifications. 2. Integrating Firebase Cloud Messaging for push notifications First, create a new file named `new_intent_action.xml` inside the `res/xml` directory: ```xml <?xml version="1.0" encoding="utf-8"?> <intent-filter> <action android:name="android.intent.action.MAIN"/> </intent-filter> ``` Next, update the `AndroidManifest.xml` file by adding the following permissions and services: ```xml <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera2" /> <uses-feature android:name="android.hardware.camera" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".IncomingCallScreen" /> <activity android:name=".OutgoingCallScreen" /> <activity android:name=".MeetingActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> </intent-filter> </activity> <!-- Add the following service declaration --> <service android:name=".FirebaseMessagingService"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> </application> ``` Now, create a new class named `FirebaseMessagingService` that will handle incoming push notifications: ```java public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService { private static final String TAG = "FirebaseMsgService"; @Override public void onMessageReceived(RemoteMessage remoteMessage) { // Handle data payload when app is in foreground or background if (remoteMessage.getData().size() > 0) { Log.d(TAG, "Message data payload: " + remoteMessage.getData()); String callerId = remoteMessage.getData().get("id"); String callerName = remoteMessage.getData().get("name"); // Create an intent to start the IncomingCallScreen activity with the given parameters Intent i = new Intent(this, MainActivity.class); i.putExtra("id", callerId); i.putExtra("name", callerName); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, i, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE); String channelId = getString(R.string.default_notification_channel_id); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.ic_stat_ic_notification) .setContentTitle("Incoming Call") .setContentText(callerName) .setPriority(NotificationCompat.PRIORITY_HIGH) // Set the intent that will fire when the user taps the notification .setContentIntent(pendingIntent) .setAutoCancel(true); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // Since android Oreo notification channel is needed. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(channelId, "Call Channel", NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } notificationManager.notify(0 /* ID of notification */, builder.build()); } } } ``` Now that we have implemented the necessary classes and XML layout files, let's move on to testing the app on multiple devices. 3. Testing the app on multiple devices To test the video calling feature between two devices, follow these steps: 1. Install the APK file generated by Android Studio on both devices. 2. Open the app on one device and click the "Call" button to initiate a call with another user's name (e.g., "John Doe"). 3. The other device should receive a push notification indicating an incoming video call from the first device. 4. Tap the notification to accept the incoming call, which will open the IncomingCallScreen activity on the second device. 5. Click the "Accept" button to start a new MeetingActivity with both users participating in the video call. 6. To end the call, click the "Hang Up" button on either device. That's it! You have now successfully built an Android video calling app using the Telecom framework, VideoSDK, and Firebase Cloud Messaging. For additional features like chat messaging and screen sharing, feel free to refer to our documentation. If you encounter any issues with the implementation, don't hesitate to reach out to us through our Discord community.
Company
Video SDK
Date published
Nov. 27, 2024
Author(s)
Video SDK Team
Word count
4900
Language
English
Hacker News points
None found.