Android OTP verification using firebase

Hello Android Lovers. Let’s see how the Android OTP verification works in Android Development using Firebase. In here I am going to design two screens. Phone number Enter screen and OTP verification screen. Let’s design those screens first.

Design 01 – Phone Number Enter Screen

In here, I am getting Full name, Phone number and the Country code. Because I am going to Register a new User by his /her phone number. Just forget the Full name. Let’s continue with phone number and country code.

Let’s see the design code.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="30dp"
    tools:context=".common.RegPhoneActivity">

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

        <LinearLayout
            android:layout_marginBottom="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
            <ImageView
                android:id="@+id/back_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:src="@drawable/general_back_icon" />
            <ImageView
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_marginTop="30dp"
                android:layout_gravity="center"
                android:src="@drawable/logo" />
            <TextView
                android:id="@+id/createAccountTitle"
                android:layout_marginTop="10dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="SIGN UP WITH PHONE"
                android:textAlignment="center"
                android:fontFamily="@font/muli_black"
                android:textColor="#ffffff"
                android:textSize="15sp"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
            
            <com.hbb20.CountryCodePicker
                android:id="@+id/country_code_picker"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:background="@drawable/black_border"
                android:padding="7dp"
                app:ccp_autoDetectCountry="true"
                app:ccp_showFlag="true"
                app:ccp_showFullName="true"
                app:ccp_showNameCode="true" />
            
            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/create_account_phone_number"
                style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:hint="Enter Phone Number"
                android:textColorHint="@color/black"
                app:boxBackgroundColor="#ffffff"
                app:boxStrokeColor="@color/black"
                app:boxStrokeWidthFocused="2dp"
                app:endIconMode="clear_text"
                app:endIconTint="@color/black"
                app:hintTextColor="#000000"
                app:startIconDrawable="@drawable/field_phone_number_icon"
                app:startIconTint="@color/black">

                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fontFamily="@font/muli_semibold"
                    android:inputType="phone"
                    android:textColor="#000000"
                    android:textCursorDrawable="@null" />
            </com.google.android.material.textfield.TextInputLayout>

            <TextView
                android:id="@+id/createAccountNextBtn"
                android:background="@drawable/button_background"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:gravity="center"
                android:layout_marginTop="30dp"
                android:layout_marginBottom="20dp"
                android:textColor="#FFFFFF"
                android:text="NEXT"/>
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

I remove the full name XML code. “TextInputLayout” is for the phone number text field and “CountryCodePicker” is for get the country code. It is a dependency. Copy this below code and paste it in the build.gradle(app) file.

//country code picker
implementation 'com.hbb20:ccp:2.3.1'

After that go to manifest file. Copy this below code and paste it in the top of <application> tag.

<uses-permission android:name="android.permission.INTERNET" />

Because we need internet access to get the OTP code and use your own background drawable file. Like orange background in my one.

Design 02 – OTP Verification Screen

Let’s go to the code.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="30dp"
    tools:context=".common.verificationActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">


        <ImageView
            android:id="@+id/back_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:src="@drawable/general_back_icon" />


        <ImageView
            android:id="@+id/forget_password_icon"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:layout_marginTop="20dp"
            android:src="@drawable/verification_icon" />

        <TextView
            android:id="@+id/forget_password_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="36dp"
            android:fontFamily="@font/muli_black"
            android:gravity="center"
            android:includeFontPadding="false"
            android:text="VERIFICATION"
            android:textAlignment="center"
            android:textAllCaps="true"
            android:textColor="#FFFFFF"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/forget_password_description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:fontFamily="@font/muli"
            android:gravity="center"
            android:text="ENTER OTP CODE TO VERIFY YOUR ACCOUNT"
            android:textAlignment="center"
            android:textColor="@color/black"
            android:textSize="15sp" />

        <com.chaos.view.PinView
            android:id="@+id/pin_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:itemCount="6"
            app:itemWidth="50dp"
            app:itemHeight="50dp"
            android:gravity="center"
            android:layout_gravity="center"
            android:textColor="#000000"
            android:layout_marginTop="20dp"
            app:lineColor="#000000"
            android:itemBackground="#ffffff"
            style="@style/PinWidget.PinView"
            android:inputType="number"
            android:cursorVisible="true"
            app:cursorColor="#000000"
            app:hideLineWhenFilled="true"
            app:itemRadius="5dp"/>

        <TextView
            android:id="@+id/verifyBtn"
            android:layout_below="@id/forget_password_phone_number"
            android:background="@drawable/button_background"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:layout_marginTop="30dp"
            android:textColor="#FFFFFF"
            android:text="VERIFY CODE"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:fontFamily="@font/muli"
            android:gravity="center"
            android:layout_marginTop="20dp"
            android:text="or"
            android:textAlignment="center"
            android:textColor="@color/black"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/goEmailRegistration"
            android:layout_below="@id/forget_password_phone_number"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:layout_marginTop="20dp"
            android:textColor="#FFFFFF"
            android:text="SIGNUP WITH EMAIL"/>

    </LinearLayout>
</RelativeLayout>

In here I am using “PinView” to design the pin view section. this also a dependency. Copy this below code and paste it in the build.gradle(app) file.

//OTP pin view design
implementation 'com.chaos.view:pinview:1.4.4'

And sync it.

Backend Part 01 – Phone Number Enter Screen’s Java file

Design part is done. Now we need to implement the backend part. Let’s get back to phone number enter screen’s Java file. First we need to connect the Firebase. If you don’t know “How to connect firebase to your Android Project“, click here to refer that. Then Enable the Phone number Authentication. If you don’t know “how to enable the phone authentication“, Click here to refer that. In this enable phone authentication article has “how to enable the email”. Don’t worry. Same step for enable phone number. Just try it. it’s easy.

Then we nee to assign our text boxes and buttons in the Java file

private TextView nextBtn;
private ImageView back_btn;
private CountryCodePicker country_code_picker;
private TextInputLayout create_account_phone_number, reg_fullname;
private FirebaseAuth mAuth;

Then inside the onCreate() method, declare those variables. Like this.

country_code_picker = findViewById(R.id.country_code_picker);
reg_fullname = findViewById(R.id.reg_phone_fullname);
create_account_phone_number = (TextInputLayout) findViewById(R.id.create_account_phone_number);

nextBtn = findViewById(R.id.createAccountNextBtn);

Then create the firebase authentication instance. like this.

mAuth = FirebaseAuth.getInstance();

I am going to develop this screen when click the Next button in the phone number enter screen, pass the phone number to the verification screen. Let’s try this. Here is the code.

nextBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String full_name = reg_fullname.getEditText().getText().toString();
                String getPhoneNumber = create_account_phone_number.getEditText().getText().toString().trim();

                if (!TextUtils.isEmpty(full_name) || !TextUtils.isEmpty(getPhoneNumber) ) {
                    if (getPhoneNumber.length() == 10 ){
                        if (getPhoneNumber.charAt(0) == '0') {
                            getPhoneNumber = getPhoneNumber.substring(1);
                        }
                        String _phoneNo =  "+" + country_code_picker.getFullNumber() + getPhoneNumber;

                        Intent goPhone = new Intent(getApplicationContext(), verificationActivity.class);
                        goPhone.putExtra("phoneNo", _phoneNo);
                        startActivity(goPhone);

                    }else {
                        create_account_phone_number.setError("need 9 digits with 0");
                    }
                }else {
                    reg_fullname.setError("Field can not be empty");
                    create_account_phone_number.setError("Field can not be empty");
                }
            }
        });

First I am checking text fields are empty or not. That is why I use this below code.

if (!TextUtils.isEmpty(full_name) || !TextUtils.isEmpty(getPhoneNumber) ) 

Then I remove when the phone number has the “0′ value. Before that, I am checking the number has 10 digits or not. Because my country has 10 digits.

 if (getPhoneNumber.length() == 10 ){
    if (getPhoneNumber.charAt(0) == '0') {
           getPhoneNumber = getPhoneNumber.substring(1);
    }
}

Then I am passing the phone number with the intent.

Backend Part 02 – Verification Screen’s Java file

Let’s get back to verification java file. First declare variables. Then assign those variables in the onCreate() method.

PinView pin_view;
private FirebaseAuth mAuth;
String codeBySystem;
TextView verifyBtn, goEmailRegistration;
pin_view = findViewById(R.id.pin_view);
mAuth = FirebaseAuth.getInstance();
verifyBtn = findViewById(R.id.verifyBtn);
goEmailRegistration = findViewById(R.id.goEmailRegistration);

Set the setOnClickListener method to the verify button. Inside that paste the below code.

String code = pin_view.getText().toString();
if (!code.isEmpty()){
    verifyCode(code);
}

Create another method, outside of the onCreate method called “verifyCode()”. And paste this code inside it.

PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeBySystem, code);
signInWithPhoneAuthCredential(credential);

Create another method called signInWithPhoneAuthCredential(PhoneAuthCredential credential) outside the onCreate method and paste this code inside it.

mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            Intent goSetuo = new Intent(verificationActivity.this, HomeActivity.class);
                            startActivity(goSetuo);
                            finish();
                        } else {
                            if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                                Toast.makeText(verificationActivity.this,"Verification not Completed",Toast.LENGTH_LONG).show();
                            }
                        }
                    }
                });

Then create another method called “sendVerificationCodeToUser”. like this.

private void sendVerificationCodeToUser(String phoneNo) {
        PhoneAuthOptions options =
                PhoneAuthOptions.newBuilder(mAuth)
                        .setPhoneNumber(phoneNo)       // Phone number to verify
                        .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
                        .setActivity(this)                 // Activity (for callback binding)
                        .setCallbacks(mCallbacks)          // OnVerificationStateChangedCallbacks
                        .build();
        PhoneAuthProvider.verifyPhoneNumber(options);
    }

After that paste this below method outsidein the onCreate method.

private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks =
            new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
        @Override
        public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
            super.onCodeSent(s, forceResendingToken);

            codeBySystem = s;
        }

        @Override
        public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
            String code = phoneAuthCredential.getSmsCode();
            if (code != null){
                pin_view.setText(code);
                verifyCode(code);
            }
        }

        @Override
        public void onVerificationFailed(@NonNull FirebaseException e) {
            Toast.makeText(verificationActivity.this,e.getMessage(),Toast.LENGTH_LONG).show();

        }
    };

Finally inside the onCreate method, paste the below code.

String _phoneNo = getIntent().getStringExtra("phoneNo");

sendVerificationCodeToUser(_phoneNo);

Okay. now ready to run. Let’s check your code with my one. Follow the below full code.

    PinView pin_view;
    private FirebaseAuth mAuth;
    String codeBySystem;
    TextView verifyBtn, goEmailRegistration;
    private ImageView back_btn;

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

        pin_view = findViewById(R.id.pin_view);
        mAuth = FirebaseAuth.getInstance();
        verifyBtn = findViewById(R.id.verifyBtn);
        goEmailRegistration = findViewById(R.id.goEmailRegistration);

        goEmailRegistration.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent goSignUpEmail = new Intent(verificationActivity.this, RegEmailActivity.class);
                startActivity(goSignUpEmail);
                finish();
            }
        });

        back_btn = findViewById(R.id.back_btn);
        back_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent goBack = new Intent(verificationActivity.this, RegPhoneActivity.class);
                startActivity(goBack);
                finish();
            }
        });
        
        String _phoneNo = getIntent().getStringExtra("phoneNo");
        sendVerificationCodeToUser(_phoneNo);

        verifyBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String code = pin_view.getText().toString();
                if (!code.isEmpty()){
                    verifyCode(code);
                }
            }
        });
        
    }

    private void sendVerificationCodeToUser(String phoneNo) {
        PhoneAuthOptions options =
                PhoneAuthOptions.newBuilder(mAuth)
                        .setPhoneNumber(phoneNo)       // Phone number to verify
                        .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
                        .setActivity(this)                 // Activity (for callback binding)
                        .setCallbacks(mCallbacks)          // OnVerificationStateChangedCallbacks
                        .build();
        PhoneAuthProvider.verifyPhoneNumber(options);
    }

    private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks =
            new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
        @Override
        public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
            super.onCodeSent(s, forceResendingToken);

            codeBySystem = s;
        }

        @Override
        public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
            String code = phoneAuthCredential.getSmsCode();
            if (code != null){
                pin_view.setText(code);
                verifyCode(code);
            }
        }

        @Override
        public void onVerificationFailed(@NonNull FirebaseException e) {
            Toast.makeText(verificationActivity.this,e.getMessage(),Toast.LENGTH_LONG).show();

        }
    };

    private void verifyCode(String code){
        PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeBySystem, code);
        signInWithPhoneAuthCredential(credential);
    }

    private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            Intent goSetuo = new Intent(verificationActivity.this, HomeActivity.class);
                            startActivity(goSetuo);
                            finish();
                        } else {
                            if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                                Toast.makeText(verificationActivity.this,"Verification not Completed",Toast.LENGTH_LONG).show();
                            }
                        }
                    }
                });
    }

Now you can run your code.

Thank you

If you are a newbie to Android. Follow and refer articles. Click below link to get started.