showing results ok

This commit is contained in:
ahmeddatexpay 2025-09-24 19:06:41 +03:00
parent 7ad09b2b5f
commit 2f8234e241
3 changed files with 220 additions and 61 deletions

View File

@ -2,20 +2,19 @@ package com.test.cardreadtest.payment;
import static android.content.Intent.getIntent; import static android.content.Intent.getIntent;
import android.app.Application;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import com.test.cardreadtest.R; import com.test.cardreadtest.R;
import com.test.cardreadtest.databinding.ActivityPaymentBinding; import com.test.cardreadtest.databinding.ActivityPaymentBinding;
import com.test.cardreadtest.posAPI.ConnectionServiceCallback; import com.test.cardreadtest.posAPI.ConnectionServiceCallback;
import com.test.cardreadtest.posAPI.POSManager; import com.test.cardreadtest.posAPI.POSManager;
import com.test.cardreadtest.posAPI.PaymentResult;
import com.test.cardreadtest.posAPI.PaymentServiceCallback; import com.test.cardreadtest.posAPI.PaymentServiceCallback;
import com.test.cardreadtest.utils.TRACE; import com.test.cardreadtest.utils.TRACE;
@ -24,9 +23,6 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
//import me.goldze.mvvmhabit.utils.ToastUtils;
public class PaymentActivity extends AppCompatActivity { public class PaymentActivity extends AppCompatActivity {
private static final String TAG = "PaymentActivity"; private static final String TAG = "PaymentActivity";
private String amount; private String amount;
@ -39,81 +35,101 @@ public class PaymentActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Simple DataBinding inflation - NO third-party dependencies
binding = ActivityPaymentBinding.inflate(getLayoutInflater()); binding = ActivityPaymentBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
// Use standard ViewModelProvider
viewModel = new ViewModelProvider(this).get(PaymentViewModel.class); viewModel = new ViewModelProvider(this).get(PaymentViewModel.class);
binding.setViewModel(viewModel); binding.setViewModel(viewModel);
binding.setLifecycleOwner(this);
initData(); initData();
setupClickListeners();
}
private void setupClickListeners() {
binding.btnCancel.setOnClickListener(v -> {
Log.d(TAG, "Cancel button clicked");
cancelTransactionAndFinish();
});
binding.btnBack.setOnClickListener(v -> {
Log.d(TAG, "Back button clicked");
cancelTransactionAndFinish();
});
}
private void cancelTransactionAndFinish() {
POSManager.getInstance().cancelTransaction();
finish();
} }
/** /**
* Initialize payment activity data * Initialize payment activity data
* Sets up initial UI state and starts transaction
*/ */
public void initData() { public void initData() {
paymentServiceCallback = new PaymentCallback(); paymentServiceCallback = new PaymentCallback();
// Get intent data
Intent intent = getIntent(); Intent intent = getIntent();
amount = intent.getStringExtra("amount"); amount = intent.getStringExtra("amount");
deviceAddress = intent.getStringExtra("deviceAddress");
// For testing, use default values if not provided
if (amount == null) amount = "1.00"; if (amount == null) amount = "1.00";
if (deviceAddress == null) deviceAddress = "UART";
viewModel.displayAmount(amount);//display to UI viewModel.displayAmount(amount);
viewModel.setStatus("Initializing...");
startTransaction(); startTransaction();
} }
/** /**
* Start payment transaction in background thread * Start payment transaction in background thread
* Handles device connection and transaction initialization
*/ */
private void startTransaction() { private void startTransaction() {
new Thread(() -> { new Thread(() -> {
// Initialize POSManager if not already done
POSManager.init(getApplicationContext()); POSManager.init(getApplicationContext());
viewModel.setWaitingStatus(true);
if(!POSManager.getInstance().isDeviceReady()){ if(!POSManager.getInstance().isDeviceReady()){
POSManager.getInstance().connect(deviceAddress, new ConnectionServiceCallback() { POSManager.getInstance().connect(deviceAddress, new ConnectionServiceCallback() {
@Override @Override
public void onRequestNoQposDetected() { public void onRequestNoQposDetected() {
runOnUiThread(() -> Log.d(TAG, "No device detected")); runOnUiThread(() -> {
viewModel.setStatus("No device detected");
viewModel.setWaitingStatus(false);
});
} }
@Override @Override
public void onRequestQposConnected() { public void onRequestQposConnected() {
runOnUiThread(() -> Log.d(TAG, "Device connected")); runOnUiThread(() -> {
viewModel.setStatus("Device connected");
});
} }
@Override @Override
public void onRequestQposDisconnected() { public void onRequestQposDisconnected() {
runOnUiThread(() -> { runOnUiThread(() -> {
Log.d(TAG, "Device disconnected"); viewModel.setStatus("Device disconnected");
finish(); viewModel.setWaitingStatus(false);
}); });
} }
}); });
} }
// Start transaction with callback
POSManager.getInstance().startTransaction(amount, paymentServiceCallback); POSManager.getInstance().startTransaction(amount, paymentServiceCallback);
}).start(); }).start();
} }
/** /**
* Inner class to handle payment callbacks * Inner class to handle payment callbacks
* Implements all payment related events and UI updates
*/ */
private class PaymentCallback implements PaymentServiceCallback { private class PaymentCallback implements PaymentServiceCallback {
@Override @Override
public void onRequestWaitingUser() { public void onRequestWaitingUser() {
runOnUiThread(() -> { runOnUiThread(() -> {
viewModel.setWaitingStatus(true); viewModel.setWaitingStatus(true);
Log.d(TAG, "Please insert/swipe/tap card"); viewModel.setStatus("Please insert/swipe/tap card");
}); });
} }
@ -127,7 +143,6 @@ public class PaymentActivity extends AppCompatActivity {
@Override @Override
public void onRequestSelectEmvApp(ArrayList<String> appList) { public void onRequestSelectEmvApp(ArrayList<String> appList) {
TRACE.d("onRequestSelectEmvApp():" + appList.toString()); TRACE.d("onRequestSelectEmvApp():" + appList.toString());
// Auto-select first app for testing
if (!appList.isEmpty()) { if (!appList.isEmpty()) {
POSManager.getInstance().selectEmvApp(0); POSManager.getInstance().selectEmvApp(0);
} }
@ -154,29 +169,53 @@ public class PaymentActivity extends AppCompatActivity {
} }
@Override @Override
public void onTransactionCompleted(com.test.cardreadtest.posAPI.PaymentResult result) { public void onTransactionCompleted(PaymentResult result) {
runOnUiThread(() -> { runOnUiThread(() -> {
Log.d(TAG, "Transaction completed: " + result.getTransactionType()); viewModel.setWaitingStatus(false);
// Display basic card info for testing viewModel.showTransactionResults(true);
String transactionType = result.getTransactionType() != null ? result.getTransactionType() : "Unknown";
viewModel.setTransactionResult(transactionType);
viewModel.setStatus("Transaction Completed");
// Display card information if available
StringBuilder cardDetails = new StringBuilder();
if (result.getMaskedPAN() != null) { if (result.getMaskedPAN() != null) {
Log.d(TAG, "Card: " + result.getMaskedPAN()); cardDetails.append("PAN: ").append(result.getMaskedPAN()).append(" ");
} }
// finish(); if (result.getCardHolderName() != null) {
cardDetails.append("Name: ").append(result.getCardHolderName()).append(" ");
}
if (result.getExpiryDate() != null) {
cardDetails.append("Exp: ").append(result.getExpiryDate());
}
if (cardDetails.length() > 0) {
viewModel.setCardInfo(cardDetails.toString());
} else {
viewModel.setCardInfo("No card details available");
}
Log.d(TAG, "Transaction completed: " + transactionType);
Log.d(TAG, "Card info: " + cardDetails.toString());
}); });
} }
@Override @Override
public void onTransactionFailed(String errorMessage, String data) { public void onTransactionFailed(String errorMessage, String data) {
runOnUiThread(() -> { runOnUiThread(() -> {
viewModel.setWaitingStatus(false);
viewModel.setTransactionResult("Failed");
viewModel.setStatus("Error: " + errorMessage);
viewModel.setCardInfo("Transaction failed");
Log.d(TAG, "Transaction failed: " + errorMessage); Log.d(TAG, "Transaction failed: " + errorMessage);
finish();
}); });
} }
@Override @Override
public void onRequestOnlineProcess(final String tlv) { public void onRequestOnlineProcess(final String tlv) {
TRACE.d("onRequestOnlineProcess" + tlv); TRACE.d("onRequestOnlineProcess" + tlv);
// For testing, just send success response
POSManager.getInstance().sendOnlineProcessResult("8A023030"); POSManager.getInstance().sendOnlineProcessResult("8A023030");
} }
@ -188,9 +227,7 @@ public class PaymentActivity extends AppCompatActivity {
@Override @Override
public void onBackPressed() { public void onBackPressed() {
// Cancel transaction and go back cancelTransactionAndFinish();
POSManager.getInstance().cancelTransaction();
super.onBackPressed();
} }
@Override @Override

View File

@ -1,19 +1,69 @@
package com.test.cardreadtest.payment; package com.test.cardreadtest.payment;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
public class PaymentViewModel extends ViewModel { public class PaymentViewModel extends ViewModel {
private MutableLiveData<String> amount = new MutableLiveData<>("Amount: --");
private MutableLiveData<String> status = new MutableLiveData<>("Status: Ready");
private MutableLiveData<String> transactionResult = new MutableLiveData<>("Transaction: Waiting...");
private MutableLiveData<String> cardInfo = new MutableLiveData<>("Card: --");
private MutableLiveData<Boolean> showProgress = new MutableLiveData<>(false);
private MutableLiveData<Boolean> showResults = new MutableLiveData<>(false);
public PaymentViewModel() { public PaymentViewModel() {
super(); super();
} }
public void displayAmount(String amount) { public MutableLiveData<String> getAmount() {
// For testing return amount;
System.out.println("Amount to display: " + amount); }
public MutableLiveData<String> getStatus() {
return status;
}
public MutableLiveData<String> getTransactionResult() {
return transactionResult;
}
public MutableLiveData<String> getCardInfo() {
return cardInfo;
}
public MutableLiveData<Boolean> getShowProgress() {
return showProgress;
}
public MutableLiveData<Boolean> getShowResults() {
return showResults;
}
public void displayAmount(String amountValue) {
amount.postValue("Amount: $" + amountValue);
}
public void setStatus(String statusText) {
status.postValue("Status: " + statusText);
}
public void setTransactionResult(String result) {
transactionResult.postValue("Transaction: " + result);
}
public void setCardInfo(String cardDetails) {
cardInfo.postValue("Card: " + cardDetails);
} }
public void setWaitingStatus(boolean waiting) { public void setWaitingStatus(boolean waiting) {
System.out.println("Waiting status: " + waiting); showProgress.postValue(waiting);
if (waiting) {
setStatus("Please insert/swipe/tap card"); // Already uses postValue internally
}
}
public void showTransactionResults(boolean show) {
showResults.postValue(show);
} }
} }

View File

@ -1,49 +1,121 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:view="http://schemas.android.com/apk/res/android">
<data> <data>
<variable <variable name="viewModel" type="com.test.cardreadtest.payment.PaymentViewModel"/>
name="viewModel"
type="com.test.cardreadtest.payment.PaymentViewModel" />
</data> </data>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:gravity="center"
android:padding="20dp"> android:padding="20dp">
<!-- Header -->
<TextView <TextView
android:id="@+id/tvAmount" android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Amount: Testing..." android:text="Payment Transaction"
android:textSize="24sp" android:textSize="24sp"
android:layout_marginBottom="30dp" android:textStyle="bold"
tools:text="Amount: $1.00" /> android:gravity="center"
<TextView
android:id="@+id/tvStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status: Ready"
android:textSize="18sp"
android:layout_marginBottom="20dp" /> android:layout_marginBottom="20dp" />
<!-- Amount Section -->
<TextView
android:id="@+id/tvAmount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.amount}"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="10dp"
tools:text="Amount: $5.00" />
<!-- Status Section -->
<TextView
android:id="@+id/tvStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.status}"
android:textSize="16sp"
android:layout_marginBottom="20dp"
tools:text="Status: Processing..." />
<!-- Progress Bar -->
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" /> android:layout_gravity="center"
android:layout_marginBottom="20dp" />
<!-- Transaction Results Section (Visible when transaction completes) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/design_default_color_primary"
android:padding="16dp"
android:layout_marginBottom="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Transaction Results"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="10dp" />
<TextView
android:id="@+id/tvTransactionResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.transactionResult}"
android:textColor="@android:color/white"
android:textSize="16sp"
android:layout_marginBottom="5dp"
tools:text="Transaction: Approved" />
<TextView
android:id="@+id/tvCardInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.cardInfo}"
android:textColor="@android:color/white"
android:textSize="14sp"
tools:text="Card: ****1234 Exp: 12/25" />
</LinearLayout>
<!-- Buttons Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<Button <Button
android:id="@+id/btnCancel" android:id="@+id/btnCancel"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Cancel Transaction" android:layout_weight="1"
android:layout_marginTop="30dp" /> android:text="Cancel"
android:layout_marginEnd="10dp" />
<Button
android:id="@+id/btnBack"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Back to Main"
android:layout_marginStart="10dp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</layout> </layout>