Updated on 2026-08-14
This commit is contained in:
parent
77c2ff30e5
commit
42b6efa391
9 changed files with 172 additions and 190 deletions
|
|
@ -51,7 +51,7 @@ public class LogFileProvider extends ContentProvider {
|
|||
Log.v(LOG_TAG,
|
||||
"Called with uri: '" + uri + "'." + uri.getLastPathSegment());
|
||||
|
||||
// Check incoming Uri against the matcher
|
||||
// check incoming Uri against the matcher
|
||||
switch (uriMatcher.match(uri)) {
|
||||
|
||||
// If it returns 1 - then it matches the Uri defined in onCreate
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ public class Logger {
|
|||
// //Checks if the app has permission to write to device storage
|
||||
// //If the app does not has permission then the user will be prompted to grant permissions
|
||||
// public static void verifyStoragePermissions(Activity activity) {
|
||||
// // Check if we have write permission
|
||||
// // check if we have write permission
|
||||
// int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
//
|
||||
// if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public class BalanceValidator {
|
|||
}
|
||||
}
|
||||
|
||||
public void Check(TangemContext ctx, Boolean attest) {
|
||||
public void check(TangemContext ctx, Boolean attest) {
|
||||
firstLine = "Verification failed";
|
||||
secondLine = "";
|
||||
TangemCard card = ctx.getCard();
|
||||
|
|
|
|||
|
|
@ -64,14 +64,10 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback
|
|||
val TAG: String = LoadedWallet::class.java.simpleName
|
||||
}
|
||||
|
||||
private lateinit var ctx: TangemContext
|
||||
private lateinit var nfcManager: NfcManager
|
||||
|
||||
private var serverApiCommon: ServerApiCommon = ServerApiCommon()
|
||||
private var serverApiTangem: ServerApiTangem = ServerApiTangem()
|
||||
|
||||
|
||||
private lateinit var ctx: TangemContext
|
||||
|
||||
private var lastTag: Tag? = null
|
||||
private var lastReadSuccess = true
|
||||
private var verifyCardTask: VerifyCardTask? = null
|
||||
|
|
@ -80,24 +76,37 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback
|
|||
private var newPIN = ""
|
||||
private var newPIN2 = ""
|
||||
private var cardProtocol: CardProtocol? = null
|
||||
private val inactiveColor: ColorStateList by lazy { resources.getColorStateList(R.color.btn_dark) }
|
||||
private val activeColor: ColorStateList by lazy { resources.getColorStateList(R.color.colorAccent) }
|
||||
private val inactiveColor: ColorStateList by lazy {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
resources.getColorStateList(R.color.btn_dark, activity?.theme)
|
||||
else
|
||||
@Suppress("DEPRECATION")
|
||||
resources.getColorStateList(R.color.btn_dark)
|
||||
}
|
||||
private val activeColor: ColorStateList by lazy {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
resources.getColorStateList(R.color.colorAccent, activity?.theme)
|
||||
else
|
||||
@Suppress("DEPRECATION")
|
||||
resources.getColorStateList(R.color.colorAccent)
|
||||
}
|
||||
private var requestCounter: Int = 0
|
||||
set(value) {
|
||||
field = value
|
||||
LOG.i(TAG, "requestCounter, set $field")
|
||||
if (field <= 0) {
|
||||
LOG.e(TAG, "+++++++++++ FINISH REFRESH")
|
||||
if (srl != null && srl.isRefreshing) srl.isRefreshing = false
|
||||
//updateViews()
|
||||
} else if (srl != null && !srl.isRefreshing) srl.isRefreshing = true
|
||||
if (srl != null && srl.isRefreshing)
|
||||
srl.isRefreshing = false
|
||||
} else if (srl != null && !srl.isRefreshing)
|
||||
srl.isRefreshing = true
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ctx = TangemContext.loadFromBundle(activity, activity?.intent?.extras)
|
||||
|
||||
nfcManager = NfcManager(activity, this)
|
||||
nfcManager = NfcManager(activity!!, this)
|
||||
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
|
||||
|
||||
lastTag = activity?.intent?.getParcelableExtra(Constant.EXTRA_LAST_DISCOVERED_TAG)
|
||||
|
|
@ -141,7 +150,7 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback
|
|||
getString(R.string.in_app) -> {
|
||||
try {
|
||||
val engine = CoinEngineFactory.create(ctx)
|
||||
val intent = Intent(Intent.ACTION_VIEW, engine!!.shareWalletUri)
|
||||
val intent = Intent(Intent.ACTION_VIEW, engine?.shareWalletUri)
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
|
|
@ -561,7 +570,7 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback
|
|||
} else {
|
||||
val validator = BalanceValidator()
|
||||
// TODO why attest=false?
|
||||
validator.Check(ctx, false)
|
||||
validator.check(ctx, false)
|
||||
context?.let { ContextCompat.getColor(it, validator.color) }?.let { tvBalanceLine1.setTextColor(it) }
|
||||
tvBalanceLine1.text = validator.firstLine
|
||||
tvBalanceLine2.text = validator.getSecondLine(false)
|
||||
|
|
@ -607,10 +616,6 @@ class LoadedWallet : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback
|
|||
btnExtract.isEnabled = false
|
||||
btnExtract.backgroundTintList = inactiveColor
|
||||
}
|
||||
|
||||
// //TODO why ???
|
||||
// ctx.error = null
|
||||
// ctx.message = null
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class VerifyCard : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback {
|
|||
super.onCreate(savedInstanceState)
|
||||
ctx = TangemContext.loadFromBundle(activity, activity?.intent?.extras)
|
||||
|
||||
nfcManager = NfcManager(activity, this)
|
||||
nfcManager = NfcManager(activity!!, this)
|
||||
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ class VerifyCard : androidx.fragment.app.Fragment(), NfcAdapter.ReaderCallback {
|
|||
|
||||
override fun onTagDiscovered(tag: Tag?) {
|
||||
try {
|
||||
nfcManager.ignoreTag(tag)
|
||||
nfcManager.ignoreTag(tag!!)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.3.20'
|
||||
ext.kotlin_version = '1.3.21'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
||||
classpath 'com.android.tools.build:gradle:3.3.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,163 +0,0 @@
|
|||
package com.tangem.tangemcard.android.reader;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.Tag;
|
||||
import android.nfc.tech.IsoDep;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.tangem.tangemcard.android.presentation.dialog.NfcEnableDialog;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NfcManager {
|
||||
public static final String TAG = NfcManager.class.getSimpleName();
|
||||
|
||||
// reader mode flags: listen for type A (not B), skipping ndef check
|
||||
private static final int READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK | NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS;
|
||||
|
||||
private NfcAdapter nfcAdapter;
|
||||
private NfcEnableDialog mEnableNfcDialog;
|
||||
private FragmentActivity activity;
|
||||
private NfcAdapter.ReaderCallback mReaderCallback;
|
||||
|
||||
private boolean broadcomWorkaround = false;
|
||||
private static final int DELAY_PRESENCE = 1500;
|
||||
|
||||
|
||||
public NfcManager(FragmentActivity activity, NfcAdapter.ReaderCallback readerCallback) {
|
||||
this.activity = activity;
|
||||
mReaderCallback = readerCallback;
|
||||
nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
// register broadcast receiver
|
||||
IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
|
||||
activity.registerReceiver(mBroadcastReceiver, filter);
|
||||
|
||||
if (nfcAdapter == null || !nfcAdapter.isEnabled())
|
||||
showNFCEnableDialog();
|
||||
else
|
||||
enableReaderMode();
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
activity.unregisterReceiver(mBroadcastReceiver);
|
||||
disableReaderMode();
|
||||
}
|
||||
|
||||
public void onStop() {
|
||||
if (mEnableNfcDialog != null) {
|
||||
mEnableNfcDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void ignoreTag(Tag tag) throws IOException {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
// nfcAdapter.ignore(tag, 500, null, null);
|
||||
// }else{
|
||||
IsoDep isoDep = IsoDep.get(tag);
|
||||
if (isoDep != null) {
|
||||
isoDep.close();
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
int errorCount = 0;
|
||||
|
||||
public void notifyReadResult(boolean success) {
|
||||
// if (success) {
|
||||
// errorCount = 0;
|
||||
// } else {
|
||||
// errorCount++;
|
||||
// }
|
||||
// if (errorCount >= 3) {
|
||||
// disableReaderMode();
|
||||
// nfcAdapter = null;
|
||||
//// Toast.makeText(activity,"NFC restarted!",Toast.LENGTH_SHORT).show();
|
||||
// activity.runOnUiThread(() -> {
|
||||
// nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
|
||||
// enableReaderMode();
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
private void showNFCEnableDialog() {
|
||||
mEnableNfcDialog = new NfcEnableDialog();
|
||||
mEnableNfcDialog.show(activity.getSupportFragmentManager(), NfcEnableDialog.Companion.getTAG());
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action == null)
|
||||
return;
|
||||
if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
|
||||
int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_ON);
|
||||
if (state == NfcAdapter.STATE_ON || state == NfcAdapter.STATE_TURNING_ON) {
|
||||
// Log.d(TAG, "state: " + state + " , dialog: " + mEnableNfcDialog);
|
||||
if (mEnableNfcDialog != null) {
|
||||
mEnableNfcDialog.dismiss();
|
||||
}
|
||||
if (state == NfcAdapter.STATE_ON) {
|
||||
enableReaderMode();
|
||||
}
|
||||
} else {
|
||||
if (mEnableNfcDialog == null || !mEnableNfcDialog.isVisible()) {
|
||||
showNFCEnableDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private void enableReaderMode() {
|
||||
Bundle options = new Bundle();
|
||||
if (broadcomWorkaround) {
|
||||
/* This is a work around for some Broadcom chipsets that does
|
||||
* the presence check by sending commands that interrupt the
|
||||
* processing of the ongoing command.
|
||||
*/
|
||||
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, DELAY_PRESENCE);
|
||||
}
|
||||
nfcAdapter.enableReaderMode(activity, mReaderCallback, READER_FLAGS, options);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private void disableReaderMode() {
|
||||
if (nfcAdapter != null) {
|
||||
nfcAdapter.disableReaderMode(activity);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int REQUEST_NFC_PERMISSIONS = 1;
|
||||
private static String[] PERMISSIONS_NFC = {
|
||||
Manifest.permission.NFC
|
||||
};
|
||||
|
||||
// checks if the app has NFC permission if the app does not has permission then the user will be prompted to grant permissions
|
||||
public static void verifyPermissions(Activity activity) {
|
||||
// Check if we have write permission
|
||||
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.NFC);
|
||||
|
||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
// We don't have permission so prompt the user
|
||||
ActivityCompat.requestPermissions(activity, PERMISSIONS_NFC, REQUEST_NFC_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package com.tangem.tangemcard.android.reader
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.nfc.NfcAdapter
|
||||
import android.nfc.Tag
|
||||
import android.nfc.tech.IsoDep
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.tangem.tangemcard.android.presentation.dialog.NfcEnableDialog
|
||||
import com.tangem.tangemcard.util.Log
|
||||
import java.io.IOException
|
||||
|
||||
class NfcManager(private val activity: FragmentActivity, private val readerCallback: NfcAdapter.ReaderCallback) {
|
||||
companion object {
|
||||
val TAG: String = NfcManager::class.java.simpleName
|
||||
|
||||
// reader mode flags: listen for type A (not B), skipping ndef check
|
||||
private const val READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK or NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS
|
||||
private const val DELAY_PRESENCE = 1500
|
||||
|
||||
private const val REQUEST_NFC_PERMISSIONS = 1
|
||||
private val PERMISSIONS_NFC = arrayOf(Manifest.permission.NFC)
|
||||
|
||||
// checks if the app has NFC permission if the app does not has permission then the user will be prompted to grant permissions
|
||||
fun verifyPermissions(activity: Activity) {
|
||||
// check if we have write permission
|
||||
val permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.NFC)
|
||||
|
||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
// we don't have permission so prompt the user
|
||||
ActivityCompat.requestPermissions(activity, PERMISSIONS_NFC, REQUEST_NFC_PERMISSIONS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val nfcAdapter: NfcAdapter? = NfcAdapter.getDefaultAdapter(activity)
|
||||
private var nfcEnableDialog: NfcEnableDialog? = null
|
||||
private val broadcomWorkaround = false
|
||||
internal var errorCount = 0
|
||||
private val mBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action ?: return
|
||||
if (action == NfcAdapter.ACTION_ADAPTER_STATE_CHANGED) {
|
||||
val state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_ON)
|
||||
if (state == NfcAdapter.STATE_ON || state == NfcAdapter.STATE_TURNING_ON) {
|
||||
Log.i(TAG, "state: $state , dialog: $nfcEnableDialog")
|
||||
nfcEnableDialog?.dismiss()
|
||||
|
||||
if (state == NfcAdapter.STATE_ON)
|
||||
enableReaderMode()
|
||||
|
||||
} else {
|
||||
if (nfcEnableDialog == null || !nfcEnableDialog!!.isVisible)
|
||||
showNFCEnableDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
// register broadcast receiver
|
||||
val filter = IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)
|
||||
activity.registerReceiver(mBroadcastReceiver, filter)
|
||||
|
||||
if (nfcAdapter == null || !nfcAdapter.isEnabled)
|
||||
showNFCEnableDialog()
|
||||
else
|
||||
enableReaderMode()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
activity.unregisterReceiver(mBroadcastReceiver)
|
||||
disableReaderMode()
|
||||
}
|
||||
|
||||
fun onStop() {
|
||||
nfcEnableDialog?.dismiss()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun ignoreTag(tag: Tag) {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
// nfcAdapter.ignore(tag, 500, null, null);
|
||||
// }else{
|
||||
val isoDep = IsoDep.get(tag)
|
||||
isoDep?.close()
|
||||
// }
|
||||
}
|
||||
|
||||
fun notifyReadResult(success: Boolean) {
|
||||
// if (success) {
|
||||
// errorCount = 0;
|
||||
// } else {
|
||||
// errorCount++;
|
||||
// }
|
||||
// if (errorCount >= 3) {
|
||||
// disableReaderMode();
|
||||
// nfcAdapter = null;
|
||||
//// Toast.makeText(activity,"NFC restarted!",Toast.LENGTH_SHORT).show();
|
||||
// activity.runOnUiThread(() -> {
|
||||
// nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
|
||||
// enableReaderMode();
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
private fun showNFCEnableDialog() {
|
||||
nfcEnableDialog = NfcEnableDialog()
|
||||
nfcEnableDialog?.show(activity.supportFragmentManager, NfcEnableDialog.TAG)
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun enableReaderMode() {
|
||||
val options = Bundle()
|
||||
if (broadcomWorkaround) {
|
||||
/* This is a work around for some Broadcom chipsets that does
|
||||
* the presence check by sending commands that interrupt the
|
||||
* processing of the ongoing command.
|
||||
*/
|
||||
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, DELAY_PRESENCE)
|
||||
}
|
||||
nfcAdapter!!.enableReaderMode(activity, readerCallback, READER_FLAGS, options)
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private fun disableReaderMode() {
|
||||
nfcAdapter?.disableReaderMode(activity)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
def spongycastle_version = "1.56.0.0"
|
||||
|
||||
implementation 'com.madgag.spongycastle:core:1.56.0.0'
|
||||
implementation 'com.madgag.spongycastle:prov:1.56.0.0'
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "com.madgag.spongycastle:core:$spongycastle_version"
|
||||
implementation "com.madgag.spongycastle:prov:$spongycastle_version"
|
||||
implementation 'net.i2p.crypto:eddsa:0.3.0'
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue