Reputation: 98
I am making an android app where the only user sign in and register method is via phone authentication. I'm having a single activity and making use of fragments.
I want to add firebase phone authentication inside the SignInFragment and make use of Firebase PhoneAuthProvider.However, this is only for activities I suppose, because I tried implementing inside my fragment and my app was crashing.
This is the code of SignInFragment.java
package com.example.XX;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseException;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
public class SignInFragment extends Fragment {
private static final String TAG ="INSIDE_SIGN_IN_FRAGMENT" ;
FirebaseAuth mAuth;
EditText xPhone;
EditText xOTP;
String codeSent;
public SignInFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_sign_in, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button getOTP=view.findViewById(R.id.button_xOTP);
Button submitButton=view.findViewById(R.id.signInbutton);
xPhone=view.findViewById(R.id.editText_xMobile);
xOTP=view.findViewById(R.id.editText_xOTP);
mAuth=FirebaseAuth.getInstance();
getOTP.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendVerificationCode();
}
});
submitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
verifyOTP();
}
});
}
private void verifyOTP(){
String tOTP=xOTP.getText().toString().trim();
if(tOTP.isEmpty()){
xOTP.setError("OTP is required!");
xOTP.requestFocus();
return;
}
if(tOTP.length()<6){
xOTP.setError("Please enter a valid OTP!");
xOTP.requestFocus();
return;
}
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeSent, tOTP);
signInWithPhoneAuthCredential(credential);
}
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener((Executor) this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = task.getResult().getUser();
// ...
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure", task.getException());
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
}
private void sendVerificationCode() {
String xMobileNumber=xPhone.getText().toString().trim();
if(xMobileNumber.isEmpty()){
xPhone.setError("Phone number is required!");
xPhone.requestFocus();
return;
}
if(xMobileNumber.length()<10){
xPhone.setError("Please enter a valid phone number!");
xPhone.requestFocus();
return;
}
PhoneAuthProvider.getInstance().verifyPhoneNumber(
xMobileNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
(Executor) this, // Activity (for callback binding) //NOT SURE ABOUT THIS
mCallbacks); // OnVerificationStateChangedCallbacks
}
PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks=new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
}
@Override
public void onVerificationFailed(@NonNull FirebaseException e) {
}
@Override
public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
super.onCodeSent(s, forceResendingToken);
codeSent=s;
}
};
}
My Logcat
LOGCAT:2020-06-10 03:59:44.148 16491-16491/com.example.XX
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.XX, PID: 16491
java.lang.ClassCastException: com.example.XX.SignInFragment cannot be cast to java.util.concurrent.Executor
at com.example.XX.SignInFragment.sendVerificationCode(SignInFragment.java:132)
at com.example.XX.SignInFragment.access$000(SignInFragment.java:29)
at com.example.XX.SignInFragment$1.onClick(SignInFragment.java:65)
at android.view.View.performClick(View.java:7201)
at android.view.View.performClickInternal(View.java:7170)
at android.view.View.access$3500(View.java:806)
at android.view.View$PerformClick.run(View.java:27582)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7695)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
I know the problem is at the executor portion, it was suggested by the IDE to make use of executor at two places. Maybe the PhoneAuth method is not for fragments. Can anyone review this or tell an alternate way to implement Firebase Phone Authentication inside a Fragment ONLY.
Upvotes: 1
Views: 2042
Reputation: 921
this
keyword is used in activity.
In fragment use getActivity()
instead of this
Replace
PhoneAuthProvider.getInstance().verifyPhoneNumber(
xMobileNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
(Executor) this, // Activity (for callback binding)
mCallbacks); // OnVerificationStateChangedCallbacks
}
with
PhoneAuthProvider.getInstance().verifyPhoneNumber(
xMobileNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
getActivity(), // Activity (for callback binding)
mCallbacks); // OnVerificationStateChangedCallbacks
}
UPDATE
To avoid app crash check:
if (codeSent == null || TextUtils.isEmpty(codeSent)) {
Toast.makeText(this, "Please wait until code received", Toast.LENGTH_SHORT).show();
return;
}
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeSent, tOTP);
signInWithPhoneAuthCredential(credential);
Upvotes: 2