basic application interface
This commit is contained in:
parent
68d476950e
commit
e3d3649dd2
@ -8,18 +8,20 @@
|
||||
|
||||
std::unique_ptr<Connector> connector = nullptr;
|
||||
|
||||
void setup(JNIEnv* env, jobject isoDepObj);
|
||||
void initSessionViaBAC();
|
||||
void setup(JNIEnv* env, jobject isoDepObj, jstring _passcode);
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_bshield_cccc_MainActivity_initNFCScan(
|
||||
JNIEnv* env,
|
||||
jobject /* this */,
|
||||
jobject isoDepObj) {
|
||||
jobject isoDepObj,
|
||||
jstring passcode) {
|
||||
|
||||
setup(env, isoDepObj);
|
||||
setup(env, isoDepObj, passcode);
|
||||
if (!connector) return 0;
|
||||
|
||||
// TODO: move to connector class
|
||||
|
||||
connector->selectDf1();
|
||||
connector->initBAC();
|
||||
|
||||
@ -31,12 +33,62 @@ Java_com_bshield_cccc_MainActivity_initNFCScan(
|
||||
connector->readEFDG15();
|
||||
|
||||
connector->readEFSOD();
|
||||
connector->activeAuthentication();
|
||||
|
||||
bytes challenge = randomBytes(8);
|
||||
connector->activeAuthentication(challenge);
|
||||
|
||||
connector->ready = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void setup(JNIEnv* env, jobject isoDepObj) {
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_bshield_cccc_MainActivity_ChallengeResponse(
|
||||
JNIEnv* env,
|
||||
jobject /* this */,
|
||||
jobject challenge_bytes) {
|
||||
if (!connector) return 0;
|
||||
// connector->activeAuthentication(challenge)
|
||||
return 1;
|
||||
};
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_bshield_cccc_MainActivity_GetBasicInfo(
|
||||
JNIEnv* env,
|
||||
jobject /* this */) {
|
||||
if (!connector) return 0;
|
||||
if (!connector->ready) return 0;
|
||||
|
||||
auto passport = connector->passport;
|
||||
|
||||
// Get the class reference of the Java class
|
||||
jclass passportDataClass = env->FindClass("com/bshield/cccc/PassportData");
|
||||
|
||||
// Create a new object of the Java class
|
||||
jobject passportDataObject = env->NewObject(passportDataClass, env->GetMethodID(passportDataClass, "<init>", "()V"));
|
||||
|
||||
// Set the values of each field
|
||||
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "country", "Ljava/lang/String;"), env->NewStringUTF(passport.country.c_str()));
|
||||
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "documentNumber", "Ljava/lang/String;"), env->NewStringUTF(passport.documentNumber.c_str()));
|
||||
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "gender", "Ljava/lang/String;"), env->NewStringUTF(passport.gender.c_str()));
|
||||
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "nationality", "Ljava/lang/String;"), env->NewStringUTF(passport.nationality.c_str()));
|
||||
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "familyName", "Ljava/lang/String;"), env->NewStringUTF(passport.familyName.c_str()));
|
||||
|
||||
// Create a Java List object and populate it with the nameComponents vector
|
||||
jclass stringClass = env->FindClass("java/lang/String");
|
||||
jobjectArray nameComponentsArray = env->NewObjectArray(passport.nameComponents.size(), stringClass, nullptr);
|
||||
for (int i = 0; i < passport.nameComponents.size(); i++) {
|
||||
env->SetObjectArrayElement(nameComponentsArray, i, env->NewStringUTF(passport.nameComponents[i].c_str()));
|
||||
}
|
||||
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "nameComponents", "Ljava/util/List;"), nameComponentsArray);
|
||||
|
||||
// Set the values of birthDate and expiryDate fields
|
||||
env->SetLongField(passportDataObject, env->GetFieldID(passportDataClass, "birthDate", "J"), (jlong) passport.birthDate);
|
||||
env->SetLongField(passportDataObject, env->GetFieldID(passportDataClass, "expiryDate", "J"), (jlong) passport.expiryDate);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
void setup(JNIEnv* env, jobject isoDepObj, jstring _passcode) {
|
||||
// Get the IsoDep class and its methods
|
||||
jclass isoDepClass = env->FindClass("android/nfc/tech/IsoDep");
|
||||
|
||||
@ -61,7 +113,11 @@ void setup(JNIEnv* env, jobject isoDepObj) {
|
||||
return vec;
|
||||
};
|
||||
|
||||
connector.reset(new Connector(transceive));
|
||||
const char *cstr = env->GetStringUTFChars(_passcode, NULL);
|
||||
std::string passcode = std::string(cstr);
|
||||
env->ReleaseStringUTFChars(_passcode, cstr);
|
||||
|
||||
connector.reset(new Connector(transceive, passcode));
|
||||
|
||||
// cannot remove, must call connect to connect
|
||||
env->CallVoidMethod(isoDepObj, connectMethod);
|
||||
|
@ -1,18 +1,34 @@
|
||||
package com.bshield.cccc
|
||||
|
||||
import android.R
|
||||
import android.app.DatePickerDialog
|
||||
import android.content.IntentFilter
|
||||
import android.nfc.NfcAdapter
|
||||
import android.nfc.NfcAdapter.ACTION_ADAPTER_STATE_CHANGED
|
||||
import android.nfc.NfcAdapter.getDefaultAdapter
|
||||
import android.nfc.tech.IsoDep
|
||||
import android.nfc.tech.*
|
||||
import android.nfc.tech.TagTechnology
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.text.InputType
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.bshield.cccc.databinding.ActivityMainBinding
|
||||
import java.util.*
|
||||
|
||||
|
||||
class PassportData {
|
||||
var country: String? = null
|
||||
var documentNumber: String? = null
|
||||
var gender: String? = null
|
||||
var nationality: String? = null
|
||||
var familyName: String? = null
|
||||
var nameComponents: List<String>? = null
|
||||
var birthDate: Long = 0
|
||||
var expiryDate: Long = 0
|
||||
var portrait: ByteArray? = null
|
||||
}
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
@ -20,6 +36,11 @@ class MainActivity : AppCompatActivity() {
|
||||
private var tagTechnology: TagTechnology? = null;
|
||||
private lateinit var nfcAdapter: NfcAdapter;
|
||||
|
||||
private lateinit var birthday: String;
|
||||
private lateinit var expirydate: String;
|
||||
|
||||
var picker: DatePickerDialog? = null;
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@ -28,6 +49,59 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
nfcAdapter = getDefaultAdapter(this);
|
||||
val filter = IntentFilter(ACTION_ADAPTER_STATE_CHANGED)
|
||||
|
||||
if(true){
|
||||
val eText = binding.birthday;
|
||||
eText.setInputType(InputType.TYPE_NULL)
|
||||
eText.setOnClickListener(object : View.OnClickListener {
|
||||
override fun onClick(v: View?) {
|
||||
val cldr: Calendar = Calendar.getInstance()
|
||||
val day: Int = cldr.get(Calendar.DAY_OF_MONTH)
|
||||
val month: Int = cldr.get(Calendar.MONTH)
|
||||
val year: Int = cldr.get(Calendar.YEAR)
|
||||
// date picker dialog
|
||||
picker = DatePickerDialog(
|
||||
this@MainActivity,
|
||||
{ view, year, monthOfYear, dayOfMonth -> setBirthDate(dayOfMonth, monthOfYear, year) },
|
||||
year,
|
||||
month,
|
||||
day
|
||||
)
|
||||
picker!!.show()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(true){
|
||||
val eText = binding.expirydate;
|
||||
eText.setInputType(android.text.InputType.TYPE_NULL)
|
||||
eText.setOnClickListener(object : android.view.View.OnClickListener {
|
||||
override fun onClick(v: android.view.View?) {
|
||||
val cldr: java.util.Calendar = java.util.Calendar.getInstance()
|
||||
val day: kotlin.Int = cldr.get(java.util.Calendar.DAY_OF_MONTH)
|
||||
val month: kotlin.Int = cldr.get(java.util.Calendar.MONTH)
|
||||
val year: kotlin.Int = cldr.get(java.util.Calendar.YEAR)
|
||||
// date picker dialog
|
||||
picker = android.app.DatePickerDialog(
|
||||
this@MainActivity,
|
||||
{ view, year, monthOfYear, dayOfMonth -> setExpiryDate(dayOfMonth, monthOfYear, year) },
|
||||
year,
|
||||
month,
|
||||
day
|
||||
)
|
||||
picker!!.show()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun setBirthDate(dayOfMonth: Int, monthOfYear: Int, year: Int) {
|
||||
birthday = "%s%02d%02d".format(year.toString().substring(2), monthOfYear + 1, dayOfMonth);
|
||||
binding.birthday.setText(birthday);
|
||||
}
|
||||
fun setExpiryDate(dayOfMonth: Int, monthOfYear: Int, year: Int) {
|
||||
expirydate = "%s%02d%02d".format(year.toString().substring(2), monthOfYear + 1, dayOfMonth);
|
||||
binding.expirydate.setText(expirydate);
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@ -44,15 +118,16 @@ class MainActivity : AppCompatActivity() {
|
||||
}, (0x1 or 0x2), null);
|
||||
|
||||
// Example of a call to a native method
|
||||
binding.sampleText.text = "nfc enabled? ${nfcAdapter.isEnabled()}"
|
||||
// binding.sampleText.text = "nfc enabled? ${nfcAdapter.isEnabled()}"
|
||||
}
|
||||
|
||||
/**
|
||||
* A native method that is implemented by the 'cccc' native library,
|
||||
* which is packaged with this application.
|
||||
*/
|
||||
external fun initNFCScan(tag: TagTechnology): Boolean
|
||||
|
||||
external fun initNFCScan(tag: TagTechnology, passcode: String): Boolean
|
||||
external fun ChallengeResponse(): Boolean
|
||||
external fun GetBasicInfo(): Boolean
|
||||
|
||||
companion object {
|
||||
// Used to load the 'cccc' library on application startup.
|
||||
@ -66,6 +141,35 @@ class MainActivity : AppCompatActivity() {
|
||||
return;
|
||||
}
|
||||
|
||||
val r = initNFCScan(tagTechnology!!);
|
||||
if (binding.idnumber.text.length != 12) {
|
||||
binding.error.text = "ID number must be 12 digits";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!::birthday.isInitialized) {
|
||||
binding.error.text = "Birthday is not entered";
|
||||
}
|
||||
if (!::expirydate.isInitialized) {
|
||||
binding.error.text = "Birthday is not entered";
|
||||
}
|
||||
|
||||
val id = binding.idnumber.text.substring(3);
|
||||
|
||||
fun checkdigit(digits: String): String {
|
||||
fun mapValue(x: Char): Int {
|
||||
return when {
|
||||
x.isDigit() -> x.toString().toInt()
|
||||
x in 'A'..'Z' -> x.toInt() - 'A'.toInt() + 10
|
||||
x == '<' -> 0
|
||||
else -> throw IllegalArgumentException("Invalid character: $x")
|
||||
}
|
||||
}
|
||||
val weights = listOf(7, 3, 1)
|
||||
val hash = digits.withIndex().sumBy { (i, c) -> mapValue(c) * weights[i % weights.size] }
|
||||
return (hash % 10).toString();
|
||||
}
|
||||
|
||||
val passcode = id + checkdigit(id) + birthday + checkdigit(birthday) + expirydate + checkdigit(expirydate);
|
||||
val r = initNFCScan(tagTechnology!!, passcode);
|
||||
}
|
||||
}
|
@ -6,8 +6,46 @@
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/idnumber"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="137dp"
|
||||
android:layout_marginBottom="144dp"
|
||||
android:hint="Nhap so chung minh nhan dan"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/expirydate"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<EditText
|
||||
android:id="@+id/birthday"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="24dp"
|
||||
android:hint="Enter birth day"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/idnumber" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/expirydate"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:hint="Enter expiry date"
|
||||
app:layout_constraintBottom_toTopOf="@+id/error"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sample_text"
|
||||
android:id="@+id/error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World!"
|
||||
@ -16,4 +54,5 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue
Block a user