Build a Zoom clone with native android and WebRTC

Nilay Paul
5 min readMar 26, 2021

without wasting any time let’s start .

Open android studio and create a project .

Select empty activity and select name and all.

Select Java as programming language.

So the plan is to build splash screen , Profile for user , Login and Signup screens.

We will use Firebase for backend .

Let’s start with the splash screen .

xml of splash….

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/custom"
tools:context=".MainActivity">

<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="TODO"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.26"
tools:srcCompat="@tools:sample/avatars" />

<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="239dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/imageView"
app:layout_constraintStart_toStartOf="@+id/imageView"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>

In mainactivity.java file copy this..

package com.example.zoomclone;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {

startActivity(new Intent(MainActivity.this,SignupActivity.class));
}
},2000);
}
}

Now if you run this you will see a spinner in the splash screen.

Next step is to handle sign in and sign up activities.

Before that let’s handle the firebase and firestore .

Head on to firebase.google.com and click on open console.

Add new project and navigate to authentication . Open docs and add dependencies in the project level gradle and app level gradle respectively.

Refer to ->

https://firebase.google.com/docs/android/setup

By right clicking on the package name (Java->package name) create an empty activity (new ->empty activity) and name it Signup activity .

Signup_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SignupActivity">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical">

<EditText
android:id="@+id/editTextTextPersonName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/buttonstyle"
android:ems="10"
android:hint="Enter username"
android:inputType="textPersonName"
android:padding="10dp" />

<EditText
android:id="@+id/emailBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/buttonstyle"
android:ems="10"
android:hint="Enter your email"
android:inputType="textEmailAddress"
android:padding="10dp" />

<EditText
android:id="@+id/PasswordBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/buttonstyle"
android:ems="10"
android:hint="Password"
android:inputType="textPassword"
android:padding="10dp" />

<Button
android:id="@+id/Create"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/pressbutton"
android:text="Create Account"
android:textColor="#F1E7E7" />

<Button
android:id="@+id/Login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/pressbutton"
android:text="Already an user ? Login"
android:textColor="#FDFCFC" />

</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

SignupActivity.java

package com.example.zoomclone;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.FirebaseFirestore;

public class SignupActivity extends AppCompatActivity {
EditText emailbox,passwordbox,namebox;
Button loginbutton,signupbutton;
FirebaseAuth firebaseauth;
FirebaseFirestore database;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signup);
emailbox =findViewById(R.id.emailBox);
passwordbox=findViewById(R.id.PasswordBox);
loginbutton =findViewById(R.id.Login);
signupbutton = findViewById(R.id.Create);
namebox = findViewById(R.id.editTextTextPersonName);
firebaseauth = FirebaseAuth.getInstance();
database = FirebaseFirestore.getInstance();
final User user = new User();
user.setEmail(emailbox.getText().toString());
user.setUsername(namebox.getText().toString());
user.setPassword(passwordbox.getText().toString());

signupbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String email,password,usename;
email = emailbox.getText().toString();
password = passwordbox.getText().toString();
usename = namebox.getText().toString();
firebaseauth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
database.collection("Users").document().set(user).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(SignupActivity.this,"Account is created",Toast.LENGTH_SHORT).show();
startActivity(new Intent(SignupActivity.this,LoginActivity.class));
}
});

}else{
Toast.makeText(SignupActivity.this,task.getException().getLocalizedMessage(),Toast.LENGTH_LONG).show();
}
}
});


}
});
loginbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(SignupActivity.this,LoginActivity.class));
}
});
}
}

In similar way create the Login activity.

In xml file of login activity add

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".LoginActivity">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical">

<EditText
android:id="@+id/emailBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/buttonstyle"
android:ems="10"
android:hint="Enter your email"
android:inputType="textEmailAddress"
android:padding="10dp" />

<EditText
android:id="@+id/PasswordBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/buttonstyle"
android:ems="10"
android:hint="Password"
android:inputType="textPassword"
android:padding="10dp" />

<Button
android:id="@+id/Login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/pressbutton"
android:text="Login"
android:textColor="#FDFCFC" />

<Button
android:id="@+id/Create"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/pressbutton"
android:text="Create Account"
android:textColor="#F1E7E7" />

</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

In LoginActivity.java add

package com.example.zoomclone;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;

public class LoginActivity extends AppCompatActivity {
EditText email,password;
Button loginbutton,signupbutton;
FirebaseAuth firebase;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
email =findViewById(R.id.emailBox);
password=findViewById(R.id.PasswordBox);
loginbutton =findViewById(R.id.Login);
signupbutton = findViewById(R.id.Create);
firebase=FirebaseAuth.getInstance();

loginbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String myemail,mypassword;
myemail = email.getText().toString();
mypassword=password.getText().toString();
firebase.signInWithEmailAndPassword(myemail,mypassword).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Toast.makeText(LoginActivity.this,"Logged in",Toast.LENGTH_SHORT).show();
startActivity(new Intent(LoginActivity.this,ProfileActivity.class));
}else{
Toast.makeText(LoginActivity.this,task.getException().getLocalizedMessage(),Toast.LENGTH_SHORT).show();
}
}
});
}
});

signupbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(LoginActivity.this,SignupActivity.class));
}
});
}
}

Now we need to add the user profile activity .

First create a new java class and add

package com.example.zoomclone;

public class User {
private String username;
private String email;
private String password;

public User(){

}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

This class is a blueprint for every user .

Set up Jitsi Sdk…

//Add this to project level gradlemaven {             url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"         }
// Add this to app gradleimplementation ('org.jitsi.react:jitsi-meet-sdk:2.+') { transitive = true }Hit sync now

In profile activity’s xml file add

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ProfileActivity">

<androidx.cardview.widget.CardView
android:layout_width="342dp"
android:layout_height="255dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:orientation="vertical"
android:padding="15dp">

<EditText
android:id="@+id/roomid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:ems="10"
android:hint="Room id"
android:inputType="textPersonName"
android:padding="10dp" />

<Button
android:id="@+id/joincall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@drawable/pressbutton"
android:padding="10dp"
android:text="Join" />

<Button
android:id="@+id/sharebutton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pressbutton"
android:text="Share" />

</LinearLayout>

</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

In ProfileActivity.Java add

package com.example.zoomclone;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;

import java.net.MalformedURLException;
import java.net.URL;

public class ProfileActivity extends AppCompatActivity {
EditText secretcodebox;
Button sharebutton,joinButton ;



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);

secretcodebox = findViewById(R.id.roomid);
sharebutton = findViewById(R.id.sharebutton);
joinButton=findViewById(R.id.joincall);
URL serverUrl;
try{
serverUrl = new URL("https://meet.jit.si");
JitsiMeetConferenceOptions defaultoptions = new JitsiMeetConferenceOptions.Builder().setServerURL(serverUrl).setWelcomePageEnabled(false).build();
JitsiMeet.setDefaultConferenceOptions(defaultoptions);
} catch (MalformedURLException e) {
e.printStackTrace();
}



joinButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
JitsiMeetConferenceOptions options = new JitsiMeetConferenceOptions.Builder().setRoom(secretcodebox.getText().toString()).setWelcomePageEnabled(false).build();
JitsiMeetActivity.launch(ProfileActivity.this,options);
}
});

}
}

Now your video calling app is ready .

Jitsi chat window

Reference ->

--

--