Safepoint Card Reading
This commit is contained in:
		
							parent
							
								
									d7617186a6
								
							
						
					
					
						commit
						124da43a1e
					
				@ -45,19 +45,14 @@ android {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
 | 
					    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
 | 
				
			||||||
    implementation libs.appcompat
 | 
					    implementation libs.appcompat
 | 
				
			||||||
    implementation libs.material
 | 
					    implementation libs.material
 | 
				
			||||||
    implementation libs.activity
 | 
					    implementation libs.activity
 | 
				
			||||||
    implementation libs.constraintlayout
 | 
					    implementation libs.constraintlayout
 | 
				
			||||||
    implementation libs.cardview
 | 
					    implementation libs.cardview
 | 
				
			||||||
    implementation 'androidx.recyclerview:recyclerview:1.3.0'
 | 
					    implementation 'androidx.recyclerview:recyclerview:1.3.0'
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // Existing PayLib
 | 
					 | 
				
			||||||
    // implementation(name: 'PayLib-release-2.0.17', ext: 'aar')
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // Tambahkan dependencies yang kompatibel dari referensi
 | 
					 | 
				
			||||||
    implementation 'com.sunmi:printerlibrary:1.0.15'
 | 
					    implementation 'com.sunmi:printerlibrary:1.0.15'
 | 
				
			||||||
    implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Test dependencies
 | 
					    // Test dependencies
 | 
				
			||||||
    testImplementation libs.junit
 | 
					    testImplementation libs.junit
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@
 | 
				
			|||||||
        tools:ignore="QueryAllPackagesPermission" />
 | 
					        tools:ignore="QueryAllPackagesPermission" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <application
 | 
					    <application
 | 
				
			||||||
 | 
					        android:name=".MyApplication"
 | 
				
			||||||
        android:allowBackup="true"
 | 
					        android:allowBackup="true"
 | 
				
			||||||
        android:dataExtractionRules="@xml/data_extraction_rules"
 | 
					        android:dataExtractionRules="@xml/data_extraction_rules"
 | 
				
			||||||
        android:fullBackupContent="@xml/backup_rules"
 | 
					        android:fullBackupContent="@xml/backup_rules"
 | 
				
			||||||
@ -71,7 +72,8 @@
 | 
				
			|||||||
            android:name=".HistoryDetailActivity"
 | 
					            android:name=".HistoryDetailActivity"
 | 
				
			||||||
            android:exported="false" />
 | 
					            android:exported="false" />
 | 
				
			||||||
        <activity
 | 
					        <activity
 | 
				
			||||||
            android:name=".CreditCardActivity"
 | 
					            android:name=".kredit.CreditCardActivity"
 | 
				
			||||||
 | 
					            style="@style/Theme.AppCompat"
 | 
				
			||||||
            android:exported="false" />
 | 
					            android:exported="false" />
 | 
				
			||||||
    </application>
 | 
					    </application>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										27
									
								
								app/src/main/java/com/example/bdkipoc/CacheHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/src/main/java/com/example/bdkipoc/CacheHelper.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Context;
 | 
				
			||||||
 | 
					import android.content.SharedPreferences;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CacheHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final String PREFERENCE_FILE_NAME = "sm_pay_demo_obj";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final String KEY_LANGUAGE = "key_language";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void saveCurrentLanguage(int language) {
 | 
				
			||||||
 | 
					        SharedPreferences sharedPreferences = MyApplication.app.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);
 | 
				
			||||||
 | 
					        int value = sharedPreferences.getInt(KEY_LANGUAGE, Constant.LANGUAGE_AUTO);
 | 
				
			||||||
 | 
					        if (value == language) return;
 | 
				
			||||||
 | 
					        SharedPreferences.Editor editor = sharedPreferences.edit();
 | 
				
			||||||
 | 
					        editor.putInt(KEY_LANGUAGE, language);
 | 
				
			||||||
 | 
					        editor.apply();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static int getCurrentLanguage() {
 | 
				
			||||||
 | 
					        SharedPreferences sharedPreferences = MyApplication.app.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);
 | 
				
			||||||
 | 
					        return sharedPreferences.getInt(KEY_LANGUAGE, Constant.LANGUAGE_AUTO);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								app/src/main/java/com/example/bdkipoc/Constant.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/src/main/java/com/example/bdkipoc/Constant.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Constant {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final String TAG = "SDKTestDemo";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final int LANGUAGE_AUTO = 0;
 | 
				
			||||||
 | 
					    public static final int LANGUAGE_ZH_CN = 1;
 | 
				
			||||||
 | 
					    public static final int LANGUAGE_EN_US = 2;
 | 
				
			||||||
 | 
					    public static final int LANGUAGE_JA_JP = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final int SCAN_MODEL_NONE = 100;
 | 
				
			||||||
 | 
					    public static final int SCAN_MODEL_P2Lite = 101;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final String SCAN_MODEL_NONE_VALUE = "NONE";
 | 
				
			||||||
 | 
					    public static final String SCAN_MODEL_P2Lite_VALUE = "P2Lite";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -19,6 +19,8 @@ import androidx.core.view.WindowInsetsCompat;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.google.android.material.button.MaterialButton;
 | 
					import com.google.android.material.button.MaterialButton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.example.bdkipoc.kredit.CreditCardActivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class MainActivity extends AppCompatActivity {
 | 
					public class MainActivity extends AppCompatActivity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private boolean isExpanded = false; // False = showing only 9 main menus, True = showing all 15 menus
 | 
					    private boolean isExpanded = false; // False = showing only 9 main menus, True = showing all 15 menus
 | 
				
			||||||
@ -158,7 +160,7 @@ public class MainActivity extends AppCompatActivity {
 | 
				
			|||||||
            if (cardView != null) {
 | 
					            if (cardView != null) {
 | 
				
			||||||
                cardView.setOnClickListener(v -> {
 | 
					                cardView.setOnClickListener(v -> {
 | 
				
			||||||
                    if (cardId == R.id.card_kartu_kredit) {
 | 
					                    if (cardId == R.id.card_kartu_kredit) {
 | 
				
			||||||
                        startActivity(new Intent(MainActivity.this, PaymentActivity.class));
 | 
					                        startActivity(new Intent(MainActivity.this, CreditCardActivity.class));
 | 
				
			||||||
                    } else if (cardId == R.id.card_kartu_debit) {
 | 
					                    } else if (cardId == R.id.card_kartu_debit) {
 | 
				
			||||||
                        startActivity(new Intent(MainActivity.this, PaymentActivity.class));
 | 
					                        startActivity(new Intent(MainActivity.this, PaymentActivity.class));
 | 
				
			||||||
                    } else if (cardId == R.id.card_qris) {
 | 
					                    } else if (cardId == R.id.card_qris) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										196
									
								
								app/src/main/java/com/example/bdkipoc/MyApplication.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								app/src/main/java/com/example/bdkipoc/MyApplication.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,196 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.app.Application;
 | 
				
			||||||
 | 
					import android.app.Service;
 | 
				
			||||||
 | 
					import android.content.ComponentName;
 | 
				
			||||||
 | 
					import android.content.Intent;
 | 
				
			||||||
 | 
					import android.content.ServiceConnection;
 | 
				
			||||||
 | 
					import android.content.res.Configuration;
 | 
				
			||||||
 | 
					import android.content.res.Resources;
 | 
				
			||||||
 | 
					import android.os.IBinder;
 | 
				
			||||||
 | 
					import android.util.DisplayMetrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.example.bdkipoc.emv.EmvTTS;
 | 
				
			||||||
 | 
					import com.example.bdkipoc.utils.LogUtil;
 | 
				
			||||||
 | 
					import com.example.bdkipoc.utils.Utility;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.emv.EMVOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.etc.ETCOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.print.PrinterOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.readcard.ReadCardOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.rfid.RFIDOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.security.BiometricManagerV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.security.DevCertManagerV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.security.NoLostKeyManagerV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.security.SecurityOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.system.BasicOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.tax.TaxOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.test.TestOptV2;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.wrapper.HCEManagerV2Wrapper;
 | 
				
			||||||
 | 
					import com.sunmi.peripheral.printer.InnerPrinterCallback;
 | 
				
			||||||
 | 
					import com.sunmi.peripheral.printer.InnerPrinterException;
 | 
				
			||||||
 | 
					import com.sunmi.peripheral.printer.InnerPrinterManager;
 | 
				
			||||||
 | 
					import com.sunmi.peripheral.printer.SunmiPrinterService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sunmi.paylib.SunmiPayKernel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class MyApplication extends Application {
 | 
				
			||||||
 | 
					    public static MyApplication app;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public BasicOptV2 basicOptV2;                   // 获取基础操作模块
 | 
				
			||||||
 | 
					    public ReadCardOptV2 readCardOptV2;             // 获取读卡模块
 | 
				
			||||||
 | 
					    public PinPadOptV2 pinPadOptV2;                 // 获取PinPad操作模块
 | 
				
			||||||
 | 
					    public SecurityOptV2 securityOptV2;             // 获取安全操作模块
 | 
				
			||||||
 | 
					    public EMVOptV2 emvOptV2;                       // 获取EMV操作模块
 | 
				
			||||||
 | 
					    public TaxOptV2 taxOptV2;                       // 获取税控操作模块
 | 
				
			||||||
 | 
					    public ETCOptV2 etcOptV2;                       // 获取ETC操作模块
 | 
				
			||||||
 | 
					    public PrinterOptV2 printerOptV2;               // 获取打印操作模块
 | 
				
			||||||
 | 
					    public TestOptV2 testOptV2;                     // 获取测试操作模块
 | 
				
			||||||
 | 
					    public DevCertManagerV2 devCertManagerV2;       // 设备证书操作模块
 | 
				
			||||||
 | 
					    public NoLostKeyManagerV2 noLostKeyManagerV2;   // NoLostKey操作模块
 | 
				
			||||||
 | 
					    public HCEManagerV2Wrapper hceV2Wrapper;        // HCE操作模块
 | 
				
			||||||
 | 
					    public RFIDOptV2 rfidOptV2;                     // RFID操作模块
 | 
				
			||||||
 | 
					    public SunmiPrinterService sunmiPrinterService; // 打印模块
 | 
				
			||||||
 | 
					    //public IScanInterface scanInterface;            // 扫码模块 (commented out)
 | 
				
			||||||
 | 
					    public BiometricManagerV2 mBiometricManagerV2;  // 生物特征模块
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private boolean connectPaySDK;//是否已连接PaySDK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onCreate() {
 | 
				
			||||||
 | 
					        super.onCreate();
 | 
				
			||||||
 | 
					        app = this;
 | 
				
			||||||
 | 
					        initLocaleLanguage();
 | 
				
			||||||
 | 
					        initEmvTTS();
 | 
				
			||||||
 | 
					        bindPrintService();
 | 
				
			||||||
 | 
					        bindPaySDKService();
 | 
				
			||||||
 | 
					        //bindScannerService(); // Commented out scanner service binding
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void initLocaleLanguage() {
 | 
				
			||||||
 | 
					        Resources resources = app.getResources();
 | 
				
			||||||
 | 
					        DisplayMetrics dm = resources.getDisplayMetrics();
 | 
				
			||||||
 | 
					        Configuration config = resources.getConfiguration();
 | 
				
			||||||
 | 
					        int showLanguage = CacheHelper.getCurrentLanguage();
 | 
				
			||||||
 | 
					        if (showLanguage == Constant.LANGUAGE_AUTO) {
 | 
				
			||||||
 | 
					            LogUtil.e(Constant.TAG, config.locale.getCountry() + "---这是系统语言");
 | 
				
			||||||
 | 
					            config.locale = Resources.getSystem().getConfiguration().locale;
 | 
				
			||||||
 | 
					        } else if (showLanguage == Constant.LANGUAGE_ZH_CN) {
 | 
				
			||||||
 | 
					            LogUtil.e(Constant.TAG, "这是中文");
 | 
				
			||||||
 | 
					            config.locale = Locale.SIMPLIFIED_CHINESE;
 | 
				
			||||||
 | 
					        } else if (showLanguage == Constant.LANGUAGE_EN_US) {
 | 
				
			||||||
 | 
					            LogUtil.e(Constant.TAG, "这是英文");
 | 
				
			||||||
 | 
					            config.locale = Locale.ENGLISH;
 | 
				
			||||||
 | 
					        } else if (showLanguage == Constant.LANGUAGE_JA_JP) {
 | 
				
			||||||
 | 
					            LogUtil.e(Constant.TAG, "这是日文");
 | 
				
			||||||
 | 
					            config.locale = Locale.JAPAN;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        resources.updateConfiguration(config, dm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onConfigurationChanged(Configuration newConfig) {
 | 
				
			||||||
 | 
					        super.onConfigurationChanged(newConfig);
 | 
				
			||||||
 | 
					        LogUtil.e(Constant.TAG, "onConfigurationChanged");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean isConnectPaySDK() {
 | 
				
			||||||
 | 
					        return connectPaySDK;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * bind PaySDK service
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void bindPaySDKService() {
 | 
				
			||||||
 | 
					        final SunmiPayKernel payKernel = SunmiPayKernel.getInstance();
 | 
				
			||||||
 | 
					        payKernel.initPaySDK(this, new SunmiPayKernel.ConnectCallback() {
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public void onConnectPaySDK() {
 | 
				
			||||||
 | 
					                LogUtil.e(Constant.TAG, "onConnectPaySDK...");
 | 
				
			||||||
 | 
					                emvOptV2 = payKernel.mEMVOptV2;
 | 
				
			||||||
 | 
					                basicOptV2 = payKernel.mBasicOptV2;
 | 
				
			||||||
 | 
					                pinPadOptV2 = payKernel.mPinPadOptV2;
 | 
				
			||||||
 | 
					                readCardOptV2 = payKernel.mReadCardOptV2;
 | 
				
			||||||
 | 
					                securityOptV2 = payKernel.mSecurityOptV2;
 | 
				
			||||||
 | 
					                taxOptV2 = payKernel.mTaxOptV2;
 | 
				
			||||||
 | 
					                etcOptV2 = payKernel.mETCOptV2;
 | 
				
			||||||
 | 
					                printerOptV2 = payKernel.mPrinterOptV2;
 | 
				
			||||||
 | 
					                testOptV2 = payKernel.mTestOptV2;
 | 
				
			||||||
 | 
					                devCertManagerV2 = payKernel.mDevCertManagerV2;
 | 
				
			||||||
 | 
					                noLostKeyManagerV2 = payKernel.mNoLostKeyManagerV2;
 | 
				
			||||||
 | 
					                mBiometricManagerV2 = payKernel.mBiometricManagerV2;
 | 
				
			||||||
 | 
					                hceV2Wrapper = payKernel.mHCEManagerV2Wrapper;
 | 
				
			||||||
 | 
					                rfidOptV2 = payKernel.mRFIDOptV2;
 | 
				
			||||||
 | 
					                connectPaySDK = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public void onDisconnectPaySDK() {
 | 
				
			||||||
 | 
					                LogUtil.e(Constant.TAG, "onDisconnectPaySDK...");
 | 
				
			||||||
 | 
					                connectPaySDK = false;
 | 
				
			||||||
 | 
					                emvOptV2 = null;
 | 
				
			||||||
 | 
					                basicOptV2 = null;
 | 
				
			||||||
 | 
					                pinPadOptV2 = null;
 | 
				
			||||||
 | 
					                readCardOptV2 = null;
 | 
				
			||||||
 | 
					                securityOptV2 = null;
 | 
				
			||||||
 | 
					                taxOptV2 = null;
 | 
				
			||||||
 | 
					                etcOptV2 = null;
 | 
				
			||||||
 | 
					                printerOptV2 = null;
 | 
				
			||||||
 | 
					                devCertManagerV2 = null;
 | 
				
			||||||
 | 
					                noLostKeyManagerV2 = null;
 | 
				
			||||||
 | 
					                mBiometricManagerV2 = null;
 | 
				
			||||||
 | 
					                rfidOptV2 = null;
 | 
				
			||||||
 | 
					                Utility.showToast(R.string.connect_fail);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * bind printer service
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void bindPrintService() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            InnerPrinterManager.getInstance().bindService(this, new InnerPrinterCallback() {
 | 
				
			||||||
 | 
					                @Override
 | 
				
			||||||
 | 
					                protected void onConnected(SunmiPrinterService service) {
 | 
				
			||||||
 | 
					                    sunmiPrinterService = service;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                @Override
 | 
				
			||||||
 | 
					                protected void onDisconnected() {
 | 
				
			||||||
 | 
					                    sunmiPrinterService = null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (InnerPrinterException e) {
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * bind scanner service (commented out)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					    public void bindScannerService() {
 | 
				
			||||||
 | 
					        Intent intent = new Intent();
 | 
				
			||||||
 | 
					        intent.setPackage("com.sunmi.scanner");
 | 
				
			||||||
 | 
					        intent.setAction("com.sunmi.scanner.IScanInterface");
 | 
				
			||||||
 | 
					        bindService(intent, new ServiceConnection() {
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public void onServiceConnected(ComponentName name, IBinder service) {
 | 
				
			||||||
 | 
					                scanInterface = IScanInterface.Stub.asInterface(service);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public void onServiceDisconnected(ComponentName name) {
 | 
				
			||||||
 | 
					                scanInterface = null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }, Service.BIND_AUTO_CREATE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void initEmvTTS() {
 | 
				
			||||||
 | 
					        EmvTTS.getInstance().init();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										145
									
								
								app/src/main/java/com/example/bdkipoc/emv/EmvTTS.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								app/src/main/java/com/example/bdkipoc/emv/EmvTTS.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc.emv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.speech.tts.TextToSpeech;
 | 
				
			||||||
 | 
					import android.speech.tts.UtteranceProgressListener;
 | 
				
			||||||
 | 
					import android.util.Log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.example.bdkipoc.MyApplication;
 | 
				
			||||||
 | 
					import com.example.bdkipoc.utils.LogUtil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public final class EmvTTS extends UtteranceProgressListener {
 | 
				
			||||||
 | 
					    private static final String TAG = "EmvTTS";
 | 
				
			||||||
 | 
					    private TextToSpeech textToSpeech;
 | 
				
			||||||
 | 
					    private boolean supportTTS;
 | 
				
			||||||
 | 
					    private ITTSProgressListener listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private EmvTTS() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static EmvTTS getInstance() {
 | 
				
			||||||
 | 
					        return SingletonHolder.INSTANCE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setTTSListener(ITTSProgressListener l) {
 | 
				
			||||||
 | 
					        listener = l;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void removeTTSListener() {
 | 
				
			||||||
 | 
					        listener = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final class SingletonHolder {
 | 
				
			||||||
 | 
					        private static final EmvTTS INSTANCE = new EmvTTS();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void init() {
 | 
				
			||||||
 | 
					        //初始化TTS对象
 | 
				
			||||||
 | 
					        destroy();
 | 
				
			||||||
 | 
					        textToSpeech = new TextToSpeech(MyApplication.app, this::onTTSInit);
 | 
				
			||||||
 | 
					        textToSpeech.setOnUtteranceProgressListener(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void play(String text) {
 | 
				
			||||||
 | 
					        play(text, "0");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void play(String text, String utteranceId) {
 | 
				
			||||||
 | 
					        if (!supportTTS) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "PinPadTTS: play TTS failed, TTS not support...");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (textToSpeech == null) {
 | 
				
			||||||
 | 
					            Log.e(TAG, "PinPadTTS: play TTS slipped, textToSpeech not init..");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Log.e(TAG, "play() text: [" + text + "]");
 | 
				
			||||||
 | 
					        textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, utteranceId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onStart(String utteranceId) {
 | 
				
			||||||
 | 
					        Log.e(TAG, "播放开始,utteranceId:" + utteranceId);
 | 
				
			||||||
 | 
					        if (listener != null) {
 | 
				
			||||||
 | 
					            listener.onStart(utteranceId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onDone(String utteranceId) {
 | 
				
			||||||
 | 
					        Log.e(TAG, "播放结束,utteranceId:" + utteranceId);
 | 
				
			||||||
 | 
					        if (listener != null) {
 | 
				
			||||||
 | 
					            listener.onDone(utteranceId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onError(String utteranceId) {
 | 
				
			||||||
 | 
					        Log.e(TAG, "播放出错,utteranceId:" + utteranceId);
 | 
				
			||||||
 | 
					        if (listener != null) {
 | 
				
			||||||
 | 
					            listener.onError(utteranceId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onStop(String utteranceId, boolean interrupted) {
 | 
				
			||||||
 | 
					        Log.e(TAG, "播放停止,utteranceId:" + utteranceId + ",interrupted:" + interrupted);
 | 
				
			||||||
 | 
					        if (listener != null) {
 | 
				
			||||||
 | 
					            listener.onStop(utteranceId, interrupted);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void stop() {
 | 
				
			||||||
 | 
					        if (textToSpeech != null) {
 | 
				
			||||||
 | 
					            int code = textToSpeech.stop();
 | 
				
			||||||
 | 
					            Log.e(TAG, "tts stop() code:" + code);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    boolean isSpeaking() {
 | 
				
			||||||
 | 
					        if (textToSpeech != null) {
 | 
				
			||||||
 | 
					            return textToSpeech.isSpeaking();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void destroy() {
 | 
				
			||||||
 | 
					        if (textToSpeech != null) {
 | 
				
			||||||
 | 
					            textToSpeech.stop();
 | 
				
			||||||
 | 
					            textToSpeech.shutdown();
 | 
				
			||||||
 | 
					            textToSpeech = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** TTS初始化回调 */
 | 
				
			||||||
 | 
					    private void onTTSInit(int status) {
 | 
				
			||||||
 | 
					        if (status != TextToSpeech.SUCCESS) {
 | 
				
			||||||
 | 
					            LogUtil.e(TAG, "PinPadTTS: init TTS failed, status:" + status);
 | 
				
			||||||
 | 
					            supportTTS = false;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        updateTtsLanguage();
 | 
				
			||||||
 | 
					        if (supportTTS) {
 | 
				
			||||||
 | 
					            textToSpeech.setPitch(1.0f);
 | 
				
			||||||
 | 
					            textToSpeech.setSpeechRate(1.0f);
 | 
				
			||||||
 | 
					            LogUtil.e(TAG, "onTTSInit() success,locale:" + textToSpeech.getVoice().getLocale());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 更新TTS语言 */
 | 
				
			||||||
 | 
					    private void updateTtsLanguage() {
 | 
				
			||||||
 | 
					        Locale locale = Locale.ENGLISH;
 | 
				
			||||||
 | 
					        int result = textToSpeech.setLanguage(locale);
 | 
				
			||||||
 | 
					        if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
 | 
				
			||||||
 | 
					            supportTTS = false; //系统不支持当前Locale对应的语音播报
 | 
				
			||||||
 | 
					            LogUtil.e(TAG, "updateTtsLanguage() failed, TTS not support in locale:" + locale);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            supportTTS = true;
 | 
				
			||||||
 | 
					            LogUtil.e(TAG, "updateTtsLanguage() success, TTS locale:" + locale);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc.emv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.speech.tts.TextToSpeech;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface ITTSProgressListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when an utterance "starts" as perceived by the caller. This will
 | 
				
			||||||
 | 
					     * be soon before audio is played back in the case of a {@link TextToSpeech#speak}
 | 
				
			||||||
 | 
					     * or before the first bytes of a file are written to the file system in the case
 | 
				
			||||||
 | 
					     * of {@link TextToSpeech#synthesizeToFile}.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param utteranceId The utterance ID of the utterance.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void onStart(String utteranceId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when an utterance has successfully completed processing.
 | 
				
			||||||
 | 
					     * All audio will have been played back by this point for audible output, and all
 | 
				
			||||||
 | 
					     * output will have been written to disk for file synthesis requests.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * This request is guaranteed to be called after {@link #onStart(String)}.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param utteranceId The utterance ID of the utterance.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void onDone(String utteranceId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when an error has occurred during processing. This can be called
 | 
				
			||||||
 | 
					     * at any point in the synthesis process. Note that there might be calls
 | 
				
			||||||
 | 
					     * to {@link #onStart(String)} for specified utteranceId but there will never
 | 
				
			||||||
 | 
					     * be a call to both {@link #onDone(String)} and {@link #onError(String)} for
 | 
				
			||||||
 | 
					     * the same utterance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param utteranceId The utterance ID of the utterance.
 | 
				
			||||||
 | 
					     * @deprecated Use {@link #onError(String, int)} instead
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @deprecated Use {@link #onError(String, int)} instead
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Deprecated
 | 
				
			||||||
 | 
					    void onError(String utteranceId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when an utterance has been stopped while in progress or flushed from the
 | 
				
			||||||
 | 
					     * synthesis queue. This can happen if a client calls {@link TextToSpeech#stop()}
 | 
				
			||||||
 | 
					     * or uses {@link TextToSpeech#QUEUE_FLUSH} as an argument with the
 | 
				
			||||||
 | 
					     * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param utteranceId The utterance ID of the utterance.
 | 
				
			||||||
 | 
					     * @param interrupted If true, then the utterance was interrupted while being synthesized
 | 
				
			||||||
 | 
					     *                    and its output is incomplete. If false, then the utterance was flushed
 | 
				
			||||||
 | 
					     *                    before the synthesis started.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void onStop(String utteranceId, boolean interrupted);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,3 +1,341 @@
 | 
				
			|||||||
public class CreditCardActivity {
 | 
					package com.example.bdkipoc.kredit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.os.Bundle;
 | 
				
			||||||
 | 
					import android.os.RemoteException;
 | 
				
			||||||
 | 
					import android.widget.Button;
 | 
				
			||||||
 | 
					import android.widget.TextView;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.appcompat.app.AppCompatActivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.example.bdkipoc.MyApplication;
 | 
				
			||||||
 | 
					import com.example.bdkipoc.R;
 | 
				
			||||||
 | 
					import com.example.bdkipoc.utils.ByteUtil;
 | 
				
			||||||
 | 
					import com.example.bdkipoc.utils.Utility;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidl.AidlConstants.CardType;
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CreditCardActivity extends AppCompatActivity {
 | 
				
			||||||
 | 
					    private TextView tvResult;
 | 
				
			||||||
 | 
					    private Button btnCheckCard;
 | 
				
			||||||
 | 
					    private boolean checkingCard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void onCreate(Bundle savedInstanceState) {
 | 
				
			||||||
 | 
					        super.onCreate(savedInstanceState);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "onCreate called");
 | 
				
			||||||
 | 
					        setContentView(R.layout.activity_credit_card);
 | 
				
			||||||
 | 
					        initView();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Check PaySDK status
 | 
				
			||||||
 | 
					        if (MyApplication.app != null) {
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "MyApplication.app exists");
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "PaySDK connected: " + MyApplication.app.isConnectPaySDK());
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "readCardOptV2 null: " + (MyApplication.app.readCardOptV2 == null));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            android.util.Log.e("CreditCard", "MyApplication.app is null");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void initView() {
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "initView called");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Setup Toolbar as ActionBar
 | 
				
			||||||
 | 
					        androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar);
 | 
				
			||||||
 | 
					        if (toolbar != null) {
 | 
				
			||||||
 | 
					            setSupportActionBar(toolbar);
 | 
				
			||||||
 | 
					            if (getSupportActionBar() != null) {
 | 
				
			||||||
 | 
					                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 | 
				
			||||||
 | 
					                getSupportActionBar().setTitle(R.string.card_test_credit_card);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        tvResult = findViewById(R.id.tv_result);
 | 
				
			||||||
 | 
					        btnCheckCard = findViewById(R.id.btn_check_card);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (btnCheckCard != null) {
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "Button found, setting click listener");
 | 
				
			||||||
 | 
					            btnCheckCard.setOnClickListener(v -> {
 | 
				
			||||||
 | 
					                android.util.Log.d("CreditCard", "Button clicked!");
 | 
				
			||||||
 | 
					                switchCheckCard();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            android.util.Log.e("CreditCard", "Button not found!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (tvResult != null) {
 | 
				
			||||||
 | 
					            tvResult.setText("Ready to scan card...");
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "TextView initialized");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            android.util.Log.e("CreditCard", "TextView not found!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean onSupportNavigateUp() {
 | 
				
			||||||
 | 
					        onBackPressed();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void switchCheckCard() {
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "switchCheckCard called, checkingCard: " + checkingCard);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (checkingCard) {
 | 
				
			||||||
 | 
					                android.util.Log.d("CreditCard", "Stopping card check");
 | 
				
			||||||
 | 
					                MyApplication.app.readCardOptV2.cancelCheckCard();
 | 
				
			||||||
 | 
					                btnCheckCard.setText(R.string.card_start_check_card);
 | 
				
			||||||
 | 
					                checkingCard = false;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                android.util.Log.d("CreditCard", "Starting card check");
 | 
				
			||||||
 | 
					                checkCreditCard();
 | 
				
			||||||
 | 
					                checkingCard = true;
 | 
				
			||||||
 | 
					                btnCheckCard.setText(R.string.card_stop_check_card);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            android.util.Log.e("CreditCard", "Error in switchCheckCard: " + e.getMessage());
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void checkCreditCard() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // Ensure PaySDK is bound first
 | 
				
			||||||
 | 
					            if (MyApplication.app == null) {
 | 
				
			||||||
 | 
					                tvResult.setText("Error: Application not initialized");
 | 
				
			||||||
 | 
					                android.util.Log.e("CreditCard", "MyApplication.app is null");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // If not connected, try to bind first
 | 
				
			||||||
 | 
					            if (!MyApplication.app.isConnectPaySDK()) {
 | 
				
			||||||
 | 
					                tvResult.setText("Connecting to PaySDK...");
 | 
				
			||||||
 | 
					                android.util.Log.d("CreditCard", "PaySDK not connected, binding service...");
 | 
				
			||||||
 | 
					                MyApplication.app.bindPaySDKService();
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                // Wait a bit and retry
 | 
				
			||||||
 | 
					                btnCheckCard.postDelayed(() -> {
 | 
				
			||||||
 | 
					                    if (MyApplication.app.isConnectPaySDK() && MyApplication.app.readCardOptV2 != null) {
 | 
				
			||||||
 | 
					                        startCardScan();
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        tvResult.setText("Error: Failed to connect to PaySDK");
 | 
				
			||||||
 | 
					                        checkingCard = false;
 | 
				
			||||||
 | 
					                        btnCheckCard.setText(R.string.card_start_check_card);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }, 2000); // Wait 2 seconds
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (MyApplication.app.readCardOptV2 == null) {
 | 
				
			||||||
 | 
					                tvResult.setText("Error: Card reader not initialized");
 | 
				
			||||||
 | 
					                android.util.Log.e("CreditCard", "readCardOptV2 is null");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            startCardScan();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					            android.util.Log.e("CreditCard", "Error in checkCreditCard: " + e.getMessage());
 | 
				
			||||||
 | 
					            tvResult.setText("Error starting card scan: " + e.getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
}
 | 
					    private void startCardScan() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            int cardType = CardType.MAGNETIC.getValue() | CardType.IC.getValue() | CardType.NFC.getValue();
 | 
				
			||||||
 | 
					            tvResult.setText("Starting card scan...\nPlease insert or swipe your card");
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Log for debugging
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "Starting checkCard with cardType: " + cardType);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            MyApplication.app.readCardOptV2.checkCard(cardType, mCheckCardCallback, 60);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					            android.util.Log.e("CreditCard", "Error in startCardScan: " + e.getMessage());
 | 
				
			||||||
 | 
					            tvResult.setText("Error starting card scan: " + e.getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final CheckCardCallbackV2 mCheckCardCallback = new CheckCardCallbackV2.Stub() {
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void findMagCard(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleMagCardResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void findICCard(String atr) throws RemoteException {
 | 
				
			||||||
 | 
					            Bundle info = new Bundle();
 | 
				
			||||||
 | 
					            info.putString("atr", atr);
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleICCardResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void findRFCard(String uuid) throws RemoteException {
 | 
				
			||||||
 | 
					            // Handle RF card detection - changed to single parameter
 | 
				
			||||||
 | 
					            Bundle info = new Bundle();
 | 
				
			||||||
 | 
					            info.putString("uuid", uuid);
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleRFCardResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void onError(int code, String message) throws RemoteException {
 | 
				
			||||||
 | 
					            Bundle info = new Bundle();
 | 
				
			||||||
 | 
					            info.putInt("code", code);
 | 
				
			||||||
 | 
					            info.putString("message", message);
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleErrorResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void findICCardEx(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleICCardResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void findRFCardEx(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleRFCardResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void onErrorEx(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					            runOnUiThread(() -> handleErrorResult(info));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void handleMagCardResult(Bundle info) {
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "=== MAGNETIC CARD DATA ===");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        String track1 = Utility.null2String(info.getString("TRACK1"));
 | 
				
			||||||
 | 
					        String track2 = Utility.null2String(info.getString("TRACK2"));
 | 
				
			||||||
 | 
					        String track3 = Utility.null2String(info.getString("TRACK3"));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Log detailed track data
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Track1: " + track1);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Track2: " + track2);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Track3: " + track3);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Log error codes if available
 | 
				
			||||||
 | 
					        int track1ErrorCode = info.getInt("track1ErrorCode", 0);
 | 
				
			||||||
 | 
					        int track2ErrorCode = info.getInt("track2ErrorCode", 0);
 | 
				
			||||||
 | 
					        int track3ErrorCode = info.getInt("track3ErrorCode", 0);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Track1 Error Code: " + track1ErrorCode);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Track2 Error Code: " + track2ErrorCode);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Track3 Error Code: " + track3ErrorCode);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Log additional info if available
 | 
				
			||||||
 | 
					        String pan = info.getString("pan", "");
 | 
				
			||||||
 | 
					        String serviceCode = info.getString("servicecode", "");
 | 
				
			||||||
 | 
					        if (!pan.isEmpty()) android.util.Log.d("CreditCard", "PAN: " + pan);
 | 
				
			||||||
 | 
					        if (!serviceCode.isEmpty()) android.util.Log.d("CreditCard", "Service Code: " + serviceCode);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder()
 | 
				
			||||||
 | 
					                .append(getString(R.string.card_mag_card_detected)).append("\n")
 | 
				
			||||||
 | 
					                .append("Track1:").append(track1).append("\n")
 | 
				
			||||||
 | 
					                .append("Track2:").append(track2).append("\n")
 | 
				
			||||||
 | 
					                .append("Track3:").append(track3);
 | 
				
			||||||
 | 
					        tvResult.setText(sb);
 | 
				
			||||||
 | 
					        switchCheckCard();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void handleICCardResult(Bundle info) {
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "=== IC CARD DATA ===");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        String atr = info.getString("atr", "");
 | 
				
			||||||
 | 
					        int cardType = info.getInt("cardType", -1);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "ATR: " + atr);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Card Type: " + cardType);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Full IC Card Data: " + bundleToString(info));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					        sb.append(getString(R.string.card_ic_card_detected)).append("\n")
 | 
				
			||||||
 | 
					                .append("ATR:").append(atr).append("\n");
 | 
				
			||||||
 | 
					        if (cardType != -1) {
 | 
				
			||||||
 | 
					            sb.append("Card Type:").append(cardType).append("\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tvResult.setText(sb);
 | 
				
			||||||
 | 
					        switchCheckCard();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void handleRFCardResult(Bundle info) {
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "=== RF/NFC CARD DATA ===");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        String uuid = info.getString("uuid", "");
 | 
				
			||||||
 | 
					        String ats = info.getString("ats", "");
 | 
				
			||||||
 | 
					        int cardType = info.getInt("cardType", -1);
 | 
				
			||||||
 | 
					        int sak = info.getInt("sak", -1);
 | 
				
			||||||
 | 
					        int cardCategory = info.getInt("cardCategory", -1);
 | 
				
			||||||
 | 
					        byte[] atqa = info.getByteArray("atqa");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "UUID: " + uuid);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "ATS: " + ats);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Card Type: " + cardType);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "SAK: " + sak);
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Card Category: " + cardCategory);
 | 
				
			||||||
 | 
					        if (atqa != null) {
 | 
				
			||||||
 | 
					            android.util.Log.d("CreditCard", "ATQA: " + ByteUtil.bytes2HexStr(atqa));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        android.util.Log.d("CreditCard", "Full RF Card Data: " + bundleToString(info));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					        sb.append("RF Card Detected").append("\n")
 | 
				
			||||||
 | 
					                .append("UUID: ").append(uuid).append("\n");
 | 
				
			||||||
 | 
					        if (!ats.isEmpty()) {
 | 
				
			||||||
 | 
					            sb.append("ATS: ").append(ats).append("\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (sak != -1) {
 | 
				
			||||||
 | 
					            sb.append("SAK: ").append(String.format("0x%02X", sak)).append("\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tvResult.setText(sb);
 | 
				
			||||||
 | 
					        switchCheckCard();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void handleErrorResult(Bundle info) {
 | 
				
			||||||
 | 
					        int code = info.getInt("code");
 | 
				
			||||||
 | 
					        String msg = info.getString("message");
 | 
				
			||||||
 | 
					        String error = "Error: " + msg + " (Code: " + code + ")";
 | 
				
			||||||
 | 
					        tvResult.setText(error);
 | 
				
			||||||
 | 
					        switchCheckCard();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void onDestroy() {
 | 
				
			||||||
 | 
					        cancelCheckCard();
 | 
				
			||||||
 | 
					        super.onDestroy();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void cancelCheckCard() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            MyApplication.app.readCardOptV2.cardOff(CardType.NFC.getValue());
 | 
				
			||||||
 | 
					            MyApplication.app.readCardOptV2.cardOff(CardType.IC.getValue());
 | 
				
			||||||
 | 
					            MyApplication.app.readCardOptV2.cancelCheckCard();
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Helper method to convert Bundle to readable string for logging
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String bundleToString(Bundle bundle) {
 | 
				
			||||||
 | 
					        if (bundle == null) return "null";
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					        sb.append("{");
 | 
				
			||||||
 | 
					        for (String key : bundle.keySet()) {
 | 
				
			||||||
 | 
					            Object value = bundle.get(key);
 | 
				
			||||||
 | 
					            sb.append(key).append("=");
 | 
				
			||||||
 | 
					            if (value instanceof byte[]) {
 | 
				
			||||||
 | 
					                sb.append(ByteUtil.bytes2HexStr((byte[]) value));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                sb.append(value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sb.append(", ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (sb.length() > 1) {
 | 
				
			||||||
 | 
					            sb.setLength(sb.length() - 2); // Remove last ", "
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sb.append("}");
 | 
				
			||||||
 | 
					        return sb.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										265
									
								
								app/src/main/java/com/example/bdkipoc/utils/ByteUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								app/src/main/java/com/example/bdkipoc/utils/ByteUtil.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,265 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.text.TextUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Arrays;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ByteUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 打印内容 */
 | 
				
			||||||
 | 
					    public static String byte2PrintHex(byte[] raw, int offset, int count) {
 | 
				
			||||||
 | 
					        if (raw == null) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (offset < 0 || offset > raw.length) {
 | 
				
			||||||
 | 
					            offset = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int end = offset + count;
 | 
				
			||||||
 | 
					        if (end > raw.length) {
 | 
				
			||||||
 | 
					            end = raw.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        StringBuilder hex = new StringBuilder();
 | 
				
			||||||
 | 
					        for (int i = offset; i < end; i++) {
 | 
				
			||||||
 | 
					            int v = raw[i] & 0xFF;
 | 
				
			||||||
 | 
					            String hv = Integer.toHexString(v);
 | 
				
			||||||
 | 
					            if (hv.length() < 2) {
 | 
				
			||||||
 | 
					                hex.append(0);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            hex.append(hv);
 | 
				
			||||||
 | 
					            hex.append(" ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (hex.length() > 0) {
 | 
				
			||||||
 | 
					            hex.deleteCharAt(hex.length() - 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return hex.toString().toUpperCase();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将字节数组转换成16进制字符串
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param bytes 源字节数组
 | 
				
			||||||
 | 
					     * @return 转换后的16进制字符串
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static String bytes2HexStr(byte... bytes) {
 | 
				
			||||||
 | 
					        if (bytes == null || bytes.length == 0) {
 | 
				
			||||||
 | 
					            return "";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return bytes2HexStr(bytes, 0, bytes.length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将字节数组转换成16进制字符串
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param src    源字节数组
 | 
				
			||||||
 | 
					     * @param offset 偏移量
 | 
				
			||||||
 | 
					     * @param len    数据长度
 | 
				
			||||||
 | 
					     * @return 转换后的16进制字符串
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static String bytes2HexStr(byte[] src, int offset, int len) {
 | 
				
			||||||
 | 
					        int end = offset + len;
 | 
				
			||||||
 | 
					        if (src == null || src.length == 0 || offset < 0 || len < 0 || end > src.length) {
 | 
				
			||||||
 | 
					            return "";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        byte[] buffer = new byte[len * 2];
 | 
				
			||||||
 | 
					        int h = 0, l = 0;
 | 
				
			||||||
 | 
					        for (int i = offset, j = 0; i < end; i++) {
 | 
				
			||||||
 | 
					            h = src[i] >> 4 & 0x0f;
 | 
				
			||||||
 | 
					            l = src[i] & 0x0f;
 | 
				
			||||||
 | 
					            buffer[j++] = (byte) (h > 9 ? h - 10 + 'A' : h + '0');
 | 
				
			||||||
 | 
					            buffer[j++] = (byte) (l > 9 ? l - 10 + 'A' : l + '0');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return new String(buffer);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static byte[] hexStr2Bytes(String hexStr) {
 | 
				
			||||||
 | 
					        if (TextUtils.isEmpty(hexStr)) {
 | 
				
			||||||
 | 
					            return new byte[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int length = hexStr.length() / 2;
 | 
				
			||||||
 | 
					        char[] chars = hexStr.toCharArray();
 | 
				
			||||||
 | 
					        byte[] b = new byte[length];
 | 
				
			||||||
 | 
					        for (int i = 0; i < length; i++) {
 | 
				
			||||||
 | 
					            b[i] = (byte) (char2Byte(chars[i * 2]) << 4 | char2Byte(chars[i * 2 + 1]));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return b;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static byte hexStr2Byte(String hexStr) {
 | 
				
			||||||
 | 
					        return (byte) Integer.parseInt(hexStr, 16);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String hexStr2Str(String hexStr) {
 | 
				
			||||||
 | 
					        String vi = "0123456789ABC DEF".trim();
 | 
				
			||||||
 | 
					        char[] array = hexStr.toCharArray();
 | 
				
			||||||
 | 
					        byte[] bytes = new byte[hexStr.length() / 2];
 | 
				
			||||||
 | 
					        int temp;
 | 
				
			||||||
 | 
					        for (int i = 0; i < bytes.length; i++) {
 | 
				
			||||||
 | 
					            char c = array[2 * i];
 | 
				
			||||||
 | 
					            temp = vi.indexOf(c) * 16;
 | 
				
			||||||
 | 
					            c = array[2 * i + 1];
 | 
				
			||||||
 | 
					            temp += vi.indexOf(c);
 | 
				
			||||||
 | 
					            bytes[i] = (byte) (temp & 0xFF);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return new String(bytes);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String hexStr2AsciiStr(String hexStr) {
 | 
				
			||||||
 | 
					        String vi = "0123456789ABC DEF".trim();
 | 
				
			||||||
 | 
					        hexStr = hexStr.trim().replace(" ", "").toUpperCase(Locale.US);
 | 
				
			||||||
 | 
					        char[] array = hexStr.toCharArray();
 | 
				
			||||||
 | 
					        byte[] bytes = new byte[hexStr.length() / 2];
 | 
				
			||||||
 | 
					        int temp = 0x00;
 | 
				
			||||||
 | 
					        for (int i = 0; i < bytes.length; i++) {
 | 
				
			||||||
 | 
					            char c = array[2 * i];
 | 
				
			||||||
 | 
					            temp = vi.indexOf(c) << 4;
 | 
				
			||||||
 | 
					            c = array[2 * i + 1];
 | 
				
			||||||
 | 
					            temp |= vi.indexOf(c);
 | 
				
			||||||
 | 
					            bytes[i] = (byte) (temp & 0xFF);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return new String(bytes);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将无符号short转换成int,大端模式(高位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static int unsignedShort2IntBE(byte[] src, int offset) {
 | 
				
			||||||
 | 
					        return (src[offset] & 0xff) << 8 | (src[offset + 1] & 0xff);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将无符号short转换成int,小端模式(低位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static int unsignedShort2IntLE(byte[] src, int offset) {
 | 
				
			||||||
 | 
					        return (src[offset] & 0xff) | (src[offset + 1] & 0xff) << 8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将无符号byte转换成int
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static int unsignedByte2Int(byte[] src, int offset) {
 | 
				
			||||||
 | 
					        return src[offset] & 0xFF;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将字节数组转换成int,大端模式(高位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static int unsignedInt2IntBE(byte[] src, int offset) {
 | 
				
			||||||
 | 
					        int result = 0;
 | 
				
			||||||
 | 
					        for (int i = offset; i < offset + 4; i++) {
 | 
				
			||||||
 | 
					            result |= (src[i] & 0xff) << (offset + 3 - i) * 8;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将字节数组转换成int,小端模式(低位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static int unsignedInt2IntLE(byte[] src, int offset) {
 | 
				
			||||||
 | 
					        int value = 0;
 | 
				
			||||||
 | 
					        for (int i = offset; i < offset + 4; i++) {
 | 
				
			||||||
 | 
					            value |= (src[i] & 0xff) << (i - offset) * 8;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将int转换成byte数组,大端模式(高位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static byte[] int2BytesBE(int src) {
 | 
				
			||||||
 | 
					        byte[] result = new byte[4];
 | 
				
			||||||
 | 
					        for (int i = 0; i < 4; i++) {
 | 
				
			||||||
 | 
					            result[i] = (byte) (src >> (3 - i) * 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将int转换成byte数组,小端模式(低位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static byte[] int2BytesLE(int src) {
 | 
				
			||||||
 | 
					        byte[] result = new byte[4];
 | 
				
			||||||
 | 
					        for (int i = 0; i < 4; i++) {
 | 
				
			||||||
 | 
					            result[i] = (byte) (src >> i * 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将short转换成byte数组,大端模式(高位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static byte[] short2BytesBE(short src) {
 | 
				
			||||||
 | 
					        byte[] result = new byte[2];
 | 
				
			||||||
 | 
					        for (int i = 0; i < 2; i++) {
 | 
				
			||||||
 | 
					            result[i] = (byte) (src >> (1 - i) * 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将short转换成byte数组,小端模式(低位在前)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static byte[] short2BytesLE(short src) {
 | 
				
			||||||
 | 
					        byte[] result = new byte[2];
 | 
				
			||||||
 | 
					        for (int i = 0; i < 2; i++) {
 | 
				
			||||||
 | 
					            result[i] = (byte) (src >> i * 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将字节数组列表合并成单个字节数组
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static byte[] concatByteArrays(byte[]... list) {
 | 
				
			||||||
 | 
					        if (list == null || list.length == 0) {
 | 
				
			||||||
 | 
					            return new byte[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return concatByteArrays(Arrays.asList(list));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将字节数组列表合并成单个字节数组
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static byte[] concatByteArrays(List<byte[]> list) {
 | 
				
			||||||
 | 
					        if (list == null || list.isEmpty()) {
 | 
				
			||||||
 | 
					            return new byte[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int totalLen = 0;
 | 
				
			||||||
 | 
					        for (byte[] b : list) {
 | 
				
			||||||
 | 
					            if (b == null || b.length == 0) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            totalLen += b.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        byte[] result = new byte[totalLen];
 | 
				
			||||||
 | 
					        int index = 0;
 | 
				
			||||||
 | 
					        for (byte[] b : list) {
 | 
				
			||||||
 | 
					            if (b == null || b.length == 0) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            System.arraycopy(b, 0, result, index, b.length);
 | 
				
			||||||
 | 
					            index += b.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Convert char to byte
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param c char
 | 
				
			||||||
 | 
					     * @return byte
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static int char2Byte(char c) {
 | 
				
			||||||
 | 
					        if (c >= 'a') {
 | 
				
			||||||
 | 
					            return (c - 'a' + 10) & 0x0f;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (c >= 'A') {
 | 
				
			||||||
 | 
					            return (c - 'A' + 10) & 0x0f;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return (c - '0') & 0x0f;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								app/src/main/java/com/example/bdkipoc/utils/LogUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								app/src/main/java/com/example/bdkipoc/utils/LogUtil.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.text.TextUtils;
 | 
				
			||||||
 | 
					import android.util.Log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class LogUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final int VERBOSE = 1;
 | 
				
			||||||
 | 
					    public static final int DEBUG = 2;
 | 
				
			||||||
 | 
					    public static final int INFO = 3;
 | 
				
			||||||
 | 
					    public static final int WARN = 4;
 | 
				
			||||||
 | 
					    public static final int ERROR = 5;
 | 
				
			||||||
 | 
					    public static final int NOTHING = 6;
 | 
				
			||||||
 | 
					    public static int LEVEL = VERBOSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void setLevel(int Level) {
 | 
				
			||||||
 | 
					        LEVEL = Level;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void v(String TAG, String msg) {
 | 
				
			||||||
 | 
					        if (LEVEL <= VERBOSE && !TextUtils.isEmpty(msg)) {
 | 
				
			||||||
 | 
					            MyLog(VERBOSE, TAG, msg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void d(String TAG, String msg) {
 | 
				
			||||||
 | 
					        if (LEVEL <= DEBUG && !TextUtils.isEmpty(msg)) {
 | 
				
			||||||
 | 
					            MyLog(DEBUG, TAG, msg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void i(String TAG, String msg) {
 | 
				
			||||||
 | 
					        if (LEVEL <= INFO && !TextUtils.isEmpty(msg)) {
 | 
				
			||||||
 | 
					            MyLog(INFO, TAG, msg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void w(String TAG, String msg) {
 | 
				
			||||||
 | 
					        if (LEVEL <= WARN && !TextUtils.isEmpty(msg)) {
 | 
				
			||||||
 | 
					            MyLog(WARN, TAG, msg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void e(String TAG, String msg) {
 | 
				
			||||||
 | 
					        if (LEVEL <= ERROR && !TextUtils.isEmpty(msg)) {
 | 
				
			||||||
 | 
					            MyLog(ERROR, TAG, msg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void MyLog(int type, String TAG, String msg) {
 | 
				
			||||||
 | 
					        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
 | 
				
			||||||
 | 
					        int index = 4;
 | 
				
			||||||
 | 
					        String className = stackTrace[index].getFileName();
 | 
				
			||||||
 | 
					        String methodName = stackTrace[index].getMethodName();
 | 
				
			||||||
 | 
					        int lineNumber = stackTrace[index].getLineNumber();
 | 
				
			||||||
 | 
					        methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
 | 
				
			||||||
 | 
					        StringBuilder stringBuilder = new StringBuilder();
 | 
				
			||||||
 | 
					        stringBuilder.append("[ (")
 | 
				
			||||||
 | 
					                .append(className)
 | 
				
			||||||
 | 
					                .append(":")
 | 
				
			||||||
 | 
					                .append(lineNumber)
 | 
				
			||||||
 | 
					                .append(")#")
 | 
				
			||||||
 | 
					                .append(methodName)
 | 
				
			||||||
 | 
					                .append(" ] ");
 | 
				
			||||||
 | 
					        stringBuilder.append(msg);
 | 
				
			||||||
 | 
					        String logStr = stringBuilder.toString();
 | 
				
			||||||
 | 
					        switch (type) {
 | 
				
			||||||
 | 
					            case VERBOSE:
 | 
				
			||||||
 | 
					                Log.v(TAG, logStr);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case DEBUG:
 | 
				
			||||||
 | 
					                Log.d(TAG, logStr);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case INFO:
 | 
				
			||||||
 | 
					                Log.i(TAG, logStr);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case WARN:
 | 
				
			||||||
 | 
					                Log.w(TAG, logStr);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case ERROR:
 | 
				
			||||||
 | 
					                Log.e(TAG, logStr);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								app/src/main/java/com/example/bdkipoc/utils/Utility.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								app/src/main/java/com/example/bdkipoc/utils/Utility.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.os.Bundle;
 | 
				
			||||||
 | 
					import android.os.Handler;
 | 
				
			||||||
 | 
					import android.os.Looper;
 | 
				
			||||||
 | 
					import android.widget.Toast;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.example.bdkipoc.MyApplication;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public final class Utility {
 | 
				
			||||||
 | 
					    private Utility() {
 | 
				
			||||||
 | 
					        throw new AssertionError("Create instance of Utility is forbidden.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Bundle对象转换成字符串 */
 | 
				
			||||||
 | 
					    public static String bundle2String(Bundle bundle) {
 | 
				
			||||||
 | 
					        return bundle2String(bundle, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 根据key排序后将Bundle内容拼接成字符串
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param bundle 要处理的bundle
 | 
				
			||||||
 | 
					     * @param order  排序规则,0-不排序,1-升序,2-降序
 | 
				
			||||||
 | 
					     * @return 拼接后的字符串
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static String bundle2String(Bundle bundle, int order) {
 | 
				
			||||||
 | 
					        if (bundle == null || bundle.keySet().isEmpty()) {
 | 
				
			||||||
 | 
					            return "";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					        List<String> list = new ArrayList<>(bundle.keySet());
 | 
				
			||||||
 | 
					        if (order == 1) { //升序
 | 
				
			||||||
 | 
					            Collections.sort(list, String::compareTo);
 | 
				
			||||||
 | 
					        } else if (order == 2) {//降序
 | 
				
			||||||
 | 
					            Collections.sort(list, Collections.reverseOrder());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (String key : list) {
 | 
				
			||||||
 | 
					            sb.append(key);
 | 
				
			||||||
 | 
					            sb.append(":");
 | 
				
			||||||
 | 
					            Object value = bundle.get(key);
 | 
				
			||||||
 | 
					            if (value instanceof byte[]) {
 | 
				
			||||||
 | 
					                sb.append(ByteUtil.bytes2HexStr((byte[]) value));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                sb.append(value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sb.append("\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (sb.length() > 0) {
 | 
				
			||||||
 | 
					            sb.deleteCharAt(sb.length() - 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return sb.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 将null转换成空串 */
 | 
				
			||||||
 | 
					    public static String null2String(String str) {
 | 
				
			||||||
 | 
					        return str == null ? "" : str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String formatStr(String format, Object... params) {
 | 
				
			||||||
 | 
					        return String.format(Locale.ENGLISH, format, params);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** check whether src is hex format */
 | 
				
			||||||
 | 
					    public static boolean checkHexValue(String src) {
 | 
				
			||||||
 | 
					        return Pattern.matches("[0-9a-fA-F]+", src);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 显示Toast */
 | 
				
			||||||
 | 
					    public static void showToast(final String msg) {
 | 
				
			||||||
 | 
					        Handler handler = new Handler(Looper.getMainLooper());
 | 
				
			||||||
 | 
					        handler.post(() -> Toast.makeText(MyApplication.app, msg, Toast.LENGTH_SHORT).show());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 显示Toast */
 | 
				
			||||||
 | 
					    public static void showToast(int resId) {
 | 
				
			||||||
 | 
					        showToast(MyApplication.app.getString(resId));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 根据结果码获取成功失败信息 */
 | 
				
			||||||
 | 
					    public static String getStateString(int code) {
 | 
				
			||||||
 | 
					        return code == 0 ? "success" : "failed, code:" + code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 根据结果状态获取成功失败信息 */
 | 
				
			||||||
 | 
					    public static String getStateString(boolean state) {
 | 
				
			||||||
 | 
					        return state ? "success" : "failed";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 将dp转成px */
 | 
				
			||||||
 | 
					    public static int dp2px(int dp) {
 | 
				
			||||||
 | 
					        float density = MyApplication.app.getResources().getDisplayMetrics().density;
 | 
				
			||||||
 | 
					        return Math.round(dp * density);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 将px转成dp */
 | 
				
			||||||
 | 
					    public static int px2dp(int px) {
 | 
				
			||||||
 | 
					        float density = MyApplication.app.getResources().getDisplayMetrics().density;
 | 
				
			||||||
 | 
					        return Math.round(px / density);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					package com.example.bdkipoc.wrapper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.os.Bundle;
 | 
				
			||||||
 | 
					import android.os.RemoteException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CheckCardCallbackV2Wrapper extends CheckCardCallbackV2.Stub {
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void findMagCard(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void findICCard(String atr) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void findRFCard(String uuid) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onError(int code, String message) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void findICCardEx(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void findRFCardEx(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onErrorEx(Bundle info) throws RemoteException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,120 +1,30 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
					<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
					 | 
				
			||||||
    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:padding="16dp"
 | 
					
 | 
				
			||||||
    tools:context=".CreditCardActivity">
 | 
					    <androidx.appcompat.widget.Toolbar
 | 
				
			||||||
 | 
					        android:id="@+id/toolbar"
 | 
				
			||||||
 | 
					        android:layout_width="match_parent"
 | 
				
			||||||
 | 
					        android:layout_height="?attr/actionBarSize"
 | 
				
			||||||
 | 
					        android:background="?attr/colorPrimary"
 | 
				
			||||||
 | 
					        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <TextView
 | 
					    <TextView
 | 
				
			||||||
        android:id="@+id/tvTitle"
 | 
					        android:id="@+id/tv_result"
 | 
				
			||||||
        android:layout_width="match_parent"
 | 
					 | 
				
			||||||
        android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
        android:text="Credit Card Payment"
 | 
					 | 
				
			||||||
        android:textSize="24sp"
 | 
					 | 
				
			||||||
        android:textStyle="bold"
 | 
					 | 
				
			||||||
        android:gravity="center"
 | 
					 | 
				
			||||||
        android:layout_marginBottom="24dp" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <TextView
 | 
					 | 
				
			||||||
        android:id="@+id/tvConnectionStatus"
 | 
					 | 
				
			||||||
        android:layout_width="match_parent"
 | 
					 | 
				
			||||||
        android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
        android:text="PaySDK Status: Connecting..."
 | 
					 | 
				
			||||||
        android:textSize="16sp"
 | 
					 | 
				
			||||||
        android:padding="12dp"
 | 
					 | 
				
			||||||
        android:background="@drawable/bg_status"
 | 
					 | 
				
			||||||
        android:layout_marginBottom="16dp" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <LinearLayout
 | 
					 | 
				
			||||||
        android:layout_width="match_parent"
 | 
					 | 
				
			||||||
        android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
        android:orientation="horizontal"
 | 
					 | 
				
			||||||
        android:layout_marginBottom="16dp">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <Button
 | 
					 | 
				
			||||||
            android:id="@+id/btnCheckStatus"
 | 
					 | 
				
			||||||
            android:layout_width="0dp"
 | 
					 | 
				
			||||||
            android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
            android:layout_weight="1"
 | 
					 | 
				
			||||||
            android:text="Check Status"
 | 
					 | 
				
			||||||
            android:layout_marginEnd="8dp" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <Button
 | 
					 | 
				
			||||||
            android:id="@+id/btnReconnect"
 | 
					 | 
				
			||||||
            android:layout_width="0dp"
 | 
					 | 
				
			||||||
            android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
            android:layout_weight="1"
 | 
					 | 
				
			||||||
            android:text="Reconnect"
 | 
					 | 
				
			||||||
            android:layout_marginStart="8dp" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    </LinearLayout>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <ScrollView
 | 
					 | 
				
			||||||
        android:layout_width="match_parent"
 | 
					        android:layout_width="match_parent"
 | 
				
			||||||
        android:layout_height="0dp"
 | 
					        android:layout_height="0dp"
 | 
				
			||||||
        android:layout_weight="1">
 | 
					        android:layout_weight="1"
 | 
				
			||||||
 | 
					        android:layout_margin="16dp"
 | 
				
			||||||
 | 
					        android:text="Ready to scan card..."
 | 
				
			||||||
 | 
					        android:gravity="top" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <LinearLayout
 | 
					    <Button
 | 
				
			||||||
            android:layout_width="match_parent"
 | 
					        android:id="@+id/btn_check_card"
 | 
				
			||||||
            android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
            android:orientation="vertical">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <TextView
 | 
					 | 
				
			||||||
                android:id="@+id/tvPaymentMethods"
 | 
					 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                android:text="Payment Methods"
 | 
					 | 
				
			||||||
                android:textSize="18sp"
 | 
					 | 
				
			||||||
                android:textStyle="bold"
 | 
					 | 
				
			||||||
                android:layout_marginBottom="12dp" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <Button
 | 
					 | 
				
			||||||
                android:id="@+id/btnReadCard"
 | 
					 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                android:text="Read Card"
 | 
					 | 
				
			||||||
                android:layout_marginBottom="8dp"
 | 
					 | 
				
			||||||
                android:enabled="false" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <Button
 | 
					 | 
				
			||||||
                android:id="@+id/btnEMVPayment"
 | 
					 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                android:text="EMV Payment"
 | 
					 | 
				
			||||||
                android:layout_marginBottom="8dp"
 | 
					 | 
				
			||||||
                android:enabled="false" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <Button
 | 
					 | 
				
			||||||
                android:id="@+id/btnPinPad"
 | 
					 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                android:text="PIN Pad Test"
 | 
					 | 
				
			||||||
                android:layout_marginBottom="8dp"
 | 
					 | 
				
			||||||
                android:enabled="false" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <Button
 | 
					 | 
				
			||||||
                android:id="@+id/btnPrintTest"
 | 
					 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                android:text="Print Test"
 | 
					 | 
				
			||||||
                android:layout_marginBottom="16dp"
 | 
					 | 
				
			||||||
                android:enabled="false" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        </LinearLayout>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    </ScrollView>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <TextView
 | 
					 | 
				
			||||||
        android:id="@+id/tvDebugInfo"
 | 
					 | 
				
			||||||
        android:layout_width="match_parent"
 | 
					        android:layout_width="match_parent"
 | 
				
			||||||
        android:layout_height="wrap_content"
 | 
					        android:layout_height="wrap_content"
 | 
				
			||||||
        android:text="Debug info will appear here..."
 | 
					        android:layout_margin="16dp"
 | 
				
			||||||
        android:textSize="12sp"
 | 
					        android:text="@string/card_start_check_card" />
 | 
				
			||||||
        android:background="#f5f5f5"
 | 
					 | 
				
			||||||
        android:padding="8dp"
 | 
					 | 
				
			||||||
        android:maxLines="3"
 | 
					 | 
				
			||||||
        android:ellipsize="end" />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
</LinearLayout>
 | 
					</LinearLayout>
 | 
				
			||||||
@ -1,7 +1,25 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<resources>
 | 
					<resources>
 | 
				
			||||||
    <color name="black">#FF000000</color>
 | 
					    <color name="colorPrimary">#3F51B5</color>
 | 
				
			||||||
    <color name="white">#FFFFFFFF</color>
 | 
					    <color name="colorPrimaryDark">#303F9F</color>
 | 
				
			||||||
 | 
					    <color name="colorAccent">#FF4081</color>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <color name="white">#FFFFFF</color>
 | 
				
			||||||
 | 
					    <color name="colorOrange">#FF6600</color>
 | 
				
			||||||
 | 
					    <color name="transparent">#00000000</color>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <color name="colorBackground">#F0F2F5</color>
 | 
				
			||||||
 | 
					    <color name="colorTextTitle">#222222</color>
 | 
				
			||||||
 | 
					    <color name="colorTextContent">#666666</color>
 | 
				
			||||||
 | 
					    <color name="colorTextHelp">#999999</color>
 | 
				
			||||||
 | 
					    <color name="colorLineColor">#d7d7d7</color>
 | 
				
			||||||
 | 
					    <color name="FD5A52">#FD5A52</color>
 | 
				
			||||||
 | 
					    <color name="CE6E6E6">#E6E6E6</color>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <color name="FF3C00">#FF3C00</color>
 | 
				
			||||||
 | 
					    <color name="C999999">#999999</color>
 | 
				
			||||||
 | 
					    <color name="black">#000000</color>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <!-- Banking App Theme Colors -->
 | 
					    <!-- Banking App Theme Colors -->
 | 
				
			||||||
    <color name="primary_blue">#1976D2</color>
 | 
					    <color name="primary_blue">#1976D2</color>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								app/src/main/res/values/dimens.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								app/src/main/res/values/dimens.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<resources>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <dimen name="smallSize">24dp</dimen>
 | 
				
			||||||
 | 
					    <dimen name="itemSize">48dp</dimen>
 | 
				
			||||||
 | 
					    <dimen name="titleSize">56dp</dimen>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</resources>
 | 
				
			||||||
@ -13,6 +13,11 @@
 | 
				
			|||||||
    <string name="payment_status_success">Payment Successful!</string>
 | 
					    <string name="payment_status_success">Payment Successful!</string>
 | 
				
			||||||
    <string name="return_main">Return to Main Screen</string>
 | 
					    <string name="return_main">Return to Main Screen</string>
 | 
				
			||||||
    <string name="main_title">POC</string>
 | 
					    <string name="main_title">POC</string>
 | 
				
			||||||
    <!-- In res/values/strings.xml -->
 | 
					    <!-- In res/values/strings.xml -->    
 | 
				
			||||||
    <string name="connect_fail">Connection to payment service failed</string>
 | 
					    <string name="card_test_credit_card">Credit Card Test</string>
 | 
				
			||||||
 | 
					    <string name="card_mag_card_detected">Magnetic Card Detected</string>
 | 
				
			||||||
 | 
					    <string name="card_ic_card_detected">IC Card Detected</string>
 | 
				
			||||||
 | 
					    <string name="card_start_check_card">Start Check Card</string>
 | 
				
			||||||
 | 
					    <string name="card_stop_check_card">Stop Check Card</string>
 | 
				
			||||||
 | 
					    <string name="connect_fail">Connection failed</string>
 | 
				
			||||||
</resources>
 | 
					</resources>
 | 
				
			||||||
@ -29,6 +29,11 @@
 | 
				
			|||||||
        <item name="titleTextAppearance">@style/ToolbarTitleStyle</item>
 | 
					        <item name="titleTextAppearance">@style/ToolbarTitleStyle</item>
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <style name="Toolbar.TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
 | 
				
			||||||
 | 
					        <item name="android:textSize">18sp</item>
 | 
				
			||||||
 | 
					        <item name="android:textColor">@android:color/white</item>
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- Numpad Button Style -->
 | 
					    <!-- Numpad Button Style -->
 | 
				
			||||||
    <style name="NumpadButton">
 | 
					    <style name="NumpadButton">
 | 
				
			||||||
        <item name="android:layout_width">0dp</item>
 | 
					        <item name="android:layout_width">0dp</item>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user