Face ID real detect face and pay, works
This commit is contained in:
parent
c6cb612c99
commit
8b892e68df
|
@ -139,4 +139,12 @@ dependencies {
|
||||||
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
|
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
|
||||||
|
|
||||||
implementation "org.java-websocket:Java-WebSocket:1.5.2"
|
implementation "org.java-websocket:Java-WebSocket:1.5.2"
|
||||||
|
|
||||||
|
// ML Kit Face Detection
|
||||||
|
implementation 'com.google.mlkit:face-detection:16.1.6'
|
||||||
|
|
||||||
|
// CameraX (optional but recommended for better camera handling)
|
||||||
|
// implementation "androidx.camera:camera-camera2:1.3.2"
|
||||||
|
// implementation "androidx.camera:camera-lifecycle:1.3.2"
|
||||||
|
// implementation "androidx.camera:camera-view:1.3.2"
|
||||||
}
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
package com.dspread.pos.utils;
|
package com.dspread.pos.faceID;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
import android.hardware.camera2.CameraAccessException;
|
import android.hardware.camera2.CameraAccessException;
|
||||||
import android.hardware.camera2.CameraCaptureSession;
|
import android.hardware.camera2.CameraCaptureSession;
|
||||||
|
@ -12,10 +13,10 @@ import android.hardware.camera2.CameraManager;
|
||||||
import android.hardware.camera2.CaptureRequest;
|
import android.hardware.camera2.CaptureRequest;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.util.Size;
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.TextureView;
|
import android.view.TextureView;
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -23,6 +24,7 @@ import java.util.Arrays;
|
||||||
public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
|
|
||||||
private static final int REQUEST_CAMERA_PERMISSION = 200;
|
private static final int REQUEST_CAMERA_PERMISSION = 200;
|
||||||
|
private static final int DETECTION_INTERVAL_MS = 1000; // Check every second
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private TextureView textureView;
|
private TextureView textureView;
|
||||||
|
@ -35,8 +37,10 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
|
|
||||||
private Handler backgroundHandler;
|
private Handler backgroundHandler;
|
||||||
private HandlerThread backgroundThread;
|
private HandlerThread backgroundThread;
|
||||||
|
|
||||||
private String frontCameraId;
|
private String frontCameraId;
|
||||||
|
private RealFaceDetector realFaceDetector;
|
||||||
|
private Handler detectionHandler;
|
||||||
|
private Runnable detectionRunnable;
|
||||||
|
|
||||||
public interface FaceIDCallback {
|
public interface FaceIDCallback {
|
||||||
void onFaceDetected();
|
void onFaceDetected();
|
||||||
|
@ -48,6 +52,26 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
this.textureView = textureView;
|
this.textureView = textureView;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
this.cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
||||||
|
|
||||||
|
// Initialize real face detector
|
||||||
|
realFaceDetector = new RealFaceDetector(context, new RealFaceDetector.FaceDetectionCallback() {
|
||||||
|
@Override
|
||||||
|
public void onFaceDetected() {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFaceDetected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFaceDetectionError(String error) {
|
||||||
|
Log.d("FaceIDHelper", "Face detection error: " + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNoFaceDetected() {
|
||||||
|
// Continue detection
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startCamera() {
|
public void startCamera() {
|
||||||
|
@ -91,6 +115,7 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
@Override
|
@Override
|
||||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||||
openCamera();
|
openCamera();
|
||||||
|
startFaceDetection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,6 +123,7 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||||
|
stopFaceDetection();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +150,6 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
public void onOpened(@NonNull CameraDevice camera) {
|
public void onOpened(@NonNull CameraDevice camera) {
|
||||||
cameraDevice = camera;
|
cameraDevice = camera;
|
||||||
createCameraPreview();
|
createCameraPreview();
|
||||||
// Simulate face detection after camera opens
|
|
||||||
simulateFaceDetection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -181,13 +205,28 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void simulateFaceDetection() {
|
private void startFaceDetection() {
|
||||||
// Simulate face detection after 3 seconds
|
detectionHandler = new Handler();
|
||||||
new Handler().postDelayed(() -> {
|
detectionRunnable = new Runnable() {
|
||||||
if (callback != null) {
|
@Override
|
||||||
callback.onFaceDetected();
|
public void run() {
|
||||||
|
if (textureView.isAvailable()) {
|
||||||
|
Bitmap frameBitmap = textureView.getBitmap();
|
||||||
|
if (frameBitmap != null) {
|
||||||
|
realFaceDetector.detectFaces(frameBitmap);
|
||||||
}
|
}
|
||||||
}, 18000);
|
}
|
||||||
|
detectionHandler.postDelayed(this, DETECTION_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
detectionHandler.postDelayed(detectionRunnable, DETECTION_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopFaceDetection() {
|
||||||
|
if (detectionHandler != null && detectionRunnable != null) {
|
||||||
|
detectionHandler.removeCallbacks(detectionRunnable);
|
||||||
|
}
|
||||||
|
realFaceDetector.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startBackgroundThread() {
|
public void startBackgroundThread() {
|
||||||
|
@ -197,6 +236,7 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopBackgroundThread() {
|
public void stopBackgroundThread() {
|
||||||
|
stopFaceDetection();
|
||||||
if (backgroundThread != null) {
|
if (backgroundThread != null) {
|
||||||
backgroundThread.quitSafely();
|
backgroundThread.quitSafely();
|
||||||
try {
|
try {
|
||||||
|
@ -210,6 +250,7 @@ public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeCamera() {
|
public void closeCamera() {
|
||||||
|
stopFaceDetection();
|
||||||
if (cameraCaptureSession != null) {
|
if (cameraCaptureSession != null) {
|
||||||
cameraCaptureSession.close();
|
cameraCaptureSession.close();
|
||||||
cameraCaptureSession = null;
|
cameraCaptureSession = null;
|
|
@ -0,0 +1,132 @@
|
||||||
|
package com.dspread.pos.faceID;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
import com.google.mlkit.vision.common.InputImage;
|
||||||
|
import com.google.mlkit.vision.face.Face;
|
||||||
|
import com.google.mlkit.vision.face.FaceDetection;
|
||||||
|
import com.google.mlkit.vision.face.FaceDetector;
|
||||||
|
import com.google.mlkit.vision.face.FaceDetectorOptions;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RealFaceDetector {
|
||||||
|
|
||||||
|
private FaceDetector faceDetector;
|
||||||
|
private FaceDetectionCallback callback;
|
||||||
|
private boolean isDetecting = false;
|
||||||
|
|
||||||
|
public interface FaceDetectionCallback {
|
||||||
|
void onFaceDetected();
|
||||||
|
void onFaceDetectionError(String error);
|
||||||
|
void onNoFaceDetected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealFaceDetector(Context context, FaceDetectionCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
initializeFaceDetector();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeFaceDetector() {
|
||||||
|
// High-accuracy landmark detection and face classification
|
||||||
|
FaceDetectorOptions options = new FaceDetectorOptions.Builder()
|
||||||
|
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
|
||||||
|
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)
|
||||||
|
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
|
||||||
|
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
|
||||||
|
.setMinFaceSize(0.15f) // Minimum face size (15% of image width)
|
||||||
|
.enableTracking() // Enable face tracking for better performance
|
||||||
|
.build();
|
||||||
|
//// Use a different face detection approach (offline-only)
|
||||||
|
//// the bundled version:
|
||||||
|
// .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
|
||||||
|
// .setContourMode(FaceDetectorOptions.CONTOUR_MODE_NONE)
|
||||||
|
// .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_NONE)
|
||||||
|
// .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_NONE)
|
||||||
|
// .build();
|
||||||
|
|
||||||
|
faceDetector = FaceDetection.getClient(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void detectFaces(Bitmap bitmap) {
|
||||||
|
if (isDetecting) return;
|
||||||
|
|
||||||
|
isDetecting = true;
|
||||||
|
InputImage image = InputImage.fromBitmap(bitmap, 0); // 0 rotation
|
||||||
|
|
||||||
|
faceDetector.process(image)
|
||||||
|
.addOnSuccessListener(faces -> {
|
||||||
|
isDetecting = false;
|
||||||
|
handleDetectionResult(faces);
|
||||||
|
})
|
||||||
|
.addOnFailureListener(e -> {
|
||||||
|
isDetecting = false;
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFaceDetectionError("Face detection failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDetectionResult(List<Face> faces) {
|
||||||
|
if (faces == null || faces.isEmpty()) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onNoFaceDetected();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have at least one good quality face
|
||||||
|
for (Face face : faces) {
|
||||||
|
if (isGoodQualityFace(face)) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFaceDetected();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach here, faces were detected but not good quality
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onNoFaceDetected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGoodQualityFace(Face face) {
|
||||||
|
// Check if face has good confidence (not occluded, good lighting)
|
||||||
|
// You can adjust these thresholds based on your requirements
|
||||||
|
|
||||||
|
// Check if eyes are open (if classification is available)
|
||||||
|
if (face.getLeftEyeOpenProbability() != null &&
|
||||||
|
face.getLeftEyeOpenProbability() < 0.3f) {
|
||||||
|
return false; // Eye probably closed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (face.getRightEyeOpenProbability() != null &&
|
||||||
|
face.getRightEyeOpenProbability() < 0.3f) {
|
||||||
|
return false; // Eye probably closed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if smiling (optional, depends on your use case)
|
||||||
|
if (face.getSmilingProbability() != null &&
|
||||||
|
face.getSmilingProbability() < 0.1f) {
|
||||||
|
// Not smiling, but this might not be necessary for payment
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check face bounding box size (should be reasonably large)
|
||||||
|
Rect bounds = face.getBoundingBox();
|
||||||
|
float sizeRatio = (float) bounds.width() * bounds.height() / (1000 * 1000); // Example ratio
|
||||||
|
if (sizeRatio < 0.1f) {
|
||||||
|
return false; // Face too small
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Good quality face
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (faceDetector != null) {
|
||||||
|
faceDetector.close();
|
||||||
|
}
|
||||||
|
isDetecting = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import android.app.Dialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
@ -13,17 +12,12 @@ import android.view.TextureView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import androidx.lifecycle.Observer;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONException;
|
import com.alibaba.fastjson.JSONException;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.dspread.pos.TerminalApplication;
|
|
||||||
import com.dspread.pos.common.enums.TransCardMode;
|
|
||||||
import com.dspread.pos.common.manager.QPOSCallbackManager;
|
import com.dspread.pos.common.manager.QPOSCallbackManager;
|
||||||
import com.dspread.pos.posAPI.POS;
|
import com.dspread.pos.posAPI.POS;
|
||||||
import com.dspread.pos.posAPI.PaymentServiceCallback;
|
import com.dspread.pos.posAPI.PaymentServiceCallback;
|
||||||
|
@ -33,7 +27,6 @@ import com.dspread.pos.ui.payment.pinkeyboard.MyKeyboardView;
|
||||||
import com.dspread.pos.ui.payment.pinkeyboard.PinPadDialog;
|
import com.dspread.pos.ui.payment.pinkeyboard.PinPadDialog;
|
||||||
import com.dspread.pos.ui.payment.pinkeyboard.PinPadView;
|
import com.dspread.pos.ui.payment.pinkeyboard.PinPadView;
|
||||||
import com.dspread.pos.utils.BitmapReadyListener;
|
import com.dspread.pos.utils.BitmapReadyListener;
|
||||||
import com.dspread.pos.utils.DevUtils;
|
|
||||||
import com.dspread.pos.utils.DeviceUtils;
|
import com.dspread.pos.utils.DeviceUtils;
|
||||||
import com.dspread.pos.utils.HandleTxnsResultUtils;
|
import com.dspread.pos.utils.HandleTxnsResultUtils;
|
||||||
import com.dspread.pos.utils.LogFileConfig;
|
import com.dspread.pos.utils.LogFileConfig;
|
||||||
|
@ -58,12 +51,10 @@ import me.goldze.mvvmhabit.utils.SPUtils;
|
||||||
import me.goldze.mvvmhabit.utils.ToastUtils;
|
import me.goldze.mvvmhabit.utils.ToastUtils;
|
||||||
|
|
||||||
// Add these imports at the top
|
// Add these imports at the top
|
||||||
import androidx.databinding.DataBindingUtil;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import com.dspread.pos_android_app.databinding.WaitingForCardBinding; // Generated binding class
|
import com.dspread.pos_android_app.databinding.WaitingForCardBinding; // Generated binding class
|
||||||
|
|
||||||
import android.widget.FrameLayout;
|
import com.dspread.pos.faceID.FaceIDHelper;
|
||||||
import com.dspread.pos.utils.FaceIDHelper;
|
|
||||||
|
|
||||||
|
|
||||||
public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, PaymentViewModel> implements PaymentServiceCallback {
|
public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, PaymentViewModel> implements PaymentServiceCallback {
|
||||||
|
@ -175,7 +166,7 @@ public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, Paymen
|
||||||
|
|
||||||
waitingViewModel.faceIDSuccess.observe(this, success -> {
|
waitingViewModel.faceIDSuccess.observe(this, success -> {
|
||||||
if (success != null && success) {
|
if (success != null && success) {
|
||||||
simulatePaymentAfterDelay();
|
// simulatePaymentAfterDelay();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -221,15 +212,20 @@ public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, Paymen
|
||||||
faceIDHelper = new FaceIDHelper(this, textureView, new FaceIDHelper.FaceIDCallback() {
|
faceIDHelper = new FaceIDHelper(this, textureView, new FaceIDHelper.FaceIDCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFaceDetected() {
|
public void onFaceDetected() {
|
||||||
|
Log.d("FaceDetection", "✅ Face detected successfully!");
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
// Face detected - proceed with payment
|
// Face detected - proceed with payment
|
||||||
closeFaceIDCamera();
|
closeFaceIDCamera();
|
||||||
waitingViewModel.simulateFaceIDSuccess();
|
// waitingViewModel.simulateFaceIDSuccess();
|
||||||
|
|
||||||
|
FaceIDMood = true;
|
||||||
|
POS.getInstance().cancelTrade();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCameraError(String error) {
|
public void onCameraError(String error) {
|
||||||
|
Log.e("FaceDetection", "❌ Face detection error: " + error);
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
ToastUtils.showShort(error);
|
ToastUtils.showShort(error);
|
||||||
closeFaceIDCamera();
|
closeFaceIDCamera();
|
||||||
|
@ -287,7 +283,7 @@ public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, Paymen
|
||||||
binding.btnSendReceipt.setVisibility(View.VISIBLE);
|
binding.btnSendReceipt.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
200 // 10 second delay
|
50 // 10 second delay
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class WaitingForCardViewModel extends BaseViewModel {
|
||||||
}
|
}
|
||||||
public void generateQRCode(String paymentData) {
|
public void generateQRCode(String paymentData) {
|
||||||
try {
|
try {
|
||||||
Bitmap qrCode = QRCodeGenerator.generateQRCode(paymentData, 500, 500);
|
Bitmap qrCode = QRCodeGenerator.generateQRCode(paymentData, 300, 300);
|
||||||
if (qrCode != null) {
|
if (qrCode != null) {
|
||||||
qrCodeBitmap.set(qrCode);
|
qrCodeBitmap.set(qrCode);
|
||||||
Log.d("QRCode", "QR code generated successfully");
|
Log.d("QRCode", "QR code generated successfully");
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
<pl.droidsonroids.gif.GifImageView
|
<pl.droidsonroids.gif.GifImageView
|
||||||
android:layout_width="98dp"
|
android:layout_width="98dp"
|
||||||
android:layout_height="124dp"
|
android:layout_height="124dp"
|
||||||
android:src="@drawable/faceid_180px" />
|
android:src="@drawable/faceid" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
@ -194,17 +194,46 @@
|
||||||
android:id="@+id/camera_container"
|
android:id="@+id/camera_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"
|
android:gravity="center"
|
||||||
|
android:visibility="visible"
|
||||||
android:background="@android:color/black">
|
android:background="@android:color/black">
|
||||||
|
|
||||||
<!-- Camera Preview will be added here programmatically -->
|
<!-- Camera Preview will be added here programmatically -->
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/camera_preview_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<!-- Camera Preview will be added here -->
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/amountOnCamera"
|
||||||
|
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="24dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
|
||||||
|
android:text="@{vm.amount + ` `+vm.currencySymbol}"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="@drawable/rounded_bg_black_50"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
tools:text="100.00" />
|
||||||
|
|
||||||
|
|
||||||
<!-- Close button for camera -->
|
<!-- Close button for camera -->
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/btn_close_camera"
|
android:id="@+id/btn_close_camera"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_margin="24dp"
|
android:layout_margin="37dp"
|
||||||
android:src="@drawable/ic_close_white"
|
android:src="@drawable/ic_close_white"
|
||||||
android:background="@drawable/rounded_bg_black_50"
|
android:background="@drawable/rounded_bg_black_50"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
|
@ -223,7 +252,7 @@
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
android:background="@drawable/rounded_bg_black_50"
|
android:background="@drawable/rounded_bg_black_50"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
Loading…
Reference in New Issue