Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ dependencies {
implementation "androidx.camera:camera-camera2:$cameraX_version"
implementation "androidx.camera:camera-lifecycle:$cameraX_version"
implementation 'com.google.android.gms:play-services-mlkit-face-detection:17.1.0'
implementation "com.google.firebase:firebase-auth:22.3.0"
}

ext {
Expand Down
87 changes: 87 additions & 0 deletions app/src/org/commcare/utils/FirebaseAuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.commcare.utils;

import android.app.Activity;
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.firebase.FirebaseException;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthOptions;
import com.google.firebase.auth.PhoneAuthProvider;

import java.util.concurrent.TimeUnit;

public class FirebaseAuthService implements OtpAuthService {

private final FirebaseAuth firebaseAuth;
private final OtpVerificationCallback callback;
private PhoneAuthOptions.Builder optionsBuilder;
private String verificationId;

public FirebaseAuthService(Activity activity, OtpVerificationCallback callback) {
this.callback = callback;
this.firebaseAuth = FirebaseAuth.getInstance();

PhoneAuthProvider.OnVerificationStateChangedCallbacks verificationCallbacks =
new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(@NonNull PhoneAuthCredential credential) {
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
FirebaseUser user = task.getResult().getUser();
callback.onSuccess(user);
} else {
callback.onFailure("Verification failed");
}
});
}

@Override
public void onVerificationFailed(@NonNull FirebaseException e) {
callback.onFailure("Verification failed: " + e.getMessage());
}

@Override
public void onCodeSent(@NonNull String verificationId,
@NonNull PhoneAuthProvider.ForceResendingToken token) {
FirebaseAuthService.this.verificationId = verificationId;
callback.onCodeSent(verificationId);
}
};

this.optionsBuilder = PhoneAuthOptions.newBuilder(firebaseAuth)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(activity)
.setCallbacks(verificationCallbacks);
}

@Override
public void requestOtp(String phoneNumber) {
optionsBuilder.setPhoneNumber(phoneNumber);
PhoneAuthOptions options = optionsBuilder.build();
PhoneAuthProvider.verifyPhoneNumber(options);
}

@Override
public void verifyOtp(String code) {
if (verificationId == null) {
callback.onFailure("No verification ID available. Request OTP first.");
return;
}

PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
FirebaseUser user = task.getResult().getUser();
callback.onSuccess(user);
} else {
callback.onFailure("OTP verification failed.");
}
});
}
}
24 changes: 24 additions & 0 deletions app/src/org/commcare/utils/OtpAuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.commcare.utils;

/**
* Interface defining the contract for OTP-based authentication operations.
* <p>
* Implementations of this interface are responsible for sending OTP codes to users
* and verifying the OTP codes they enter.
*/
public interface OtpAuthService {

/**
* Sends an OTP to the specified phone number.
*
* @param phoneNumber The recipient's phone number in a valid format
*/
void requestOtp(String phoneNumber);

/**
* Verifies the OTP code entered by the user.
*
* @param code The OTP code to verify
*/
void verifyOtp(String code);
}
35 changes: 35 additions & 0 deletions app/src/org/commcare/utils/OtpManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.commcare.utils;

import android.app.Activity;

/**
* Manager class that wraps authentication service operations for OTP (One-Time Password) functionality.
*/
public class OtpManager {

private final OtpAuthService authService;

/**
* Constructs an OtpManager by instantiating a default FirebaseAuthService internally.
*
* @param activity The calling activity, required by FirebaseAuth
* @param callback Callback to handle OTP verification events
*/
public OtpManager(Activity activity, OtpVerificationCallback callback) {
this.authService = new FirebaseAuthService(activity, callback);
}

public void requestOtp(String phoneNumber) {
if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
throw new IllegalArgumentException("Phone number cannot be null or empty");
}
authService.requestOtp(phoneNumber);
}

public void submitOtp(String code) {
if (code == null || code.trim().isEmpty()) {
throw new IllegalArgumentException("OTP code cannot be null or empty");
}
authService.verifyOtp(code);
}
}
33 changes: 33 additions & 0 deletions app/src/org/commcare/utils/OtpVerificationCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.commcare.utils;

import com.google.firebase.auth.FirebaseUser;

/**
* Callback interface for OTP (One-Time Password) verification operations.
* <p>
* Implementations of this interface receive notifications about different stages
* of the OTP process, such as code being sent, successful verification, or failure.
*/
public interface OtpVerificationCallback {

/**
* Called when an OTP code has been successfully sent to the user's phone.
*
* @param verificationId A unique identifier for this verification session
*/
void onCodeSent(String verificationId);

/**
* Called when OTP verification completes successfully.
*
* @param user The authenticated {@link FirebaseUser}
*/
void onSuccess(FirebaseUser user);

/**
* Called when an error occurs during the OTP process.
*
* @param errorMessage A description of the error that occurred
*/
void onFailure(String errorMessage);
}
Loading