Updated on 2026-08-14

This commit is contained in:
Tangem 2018-06-09 18:49:26 +03:00
parent 5ac02ecf5b
commit bc0a1a8b48
30 changed files with 604 additions and 1825 deletions

View file

@ -41,17 +41,15 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="com.tangem.presentation.activity.MainActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:host="www.tangem.com"
android:scheme="http"/>
@ -64,75 +62,73 @@
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter"/>
</activity>
<activity
android:name="com.tangem.presentation.activity.RequestPINActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.EmptyWalletActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.SelectBlockchainActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.SavePINActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.CardInfoActivity"
android:label="@string/title_activity_card_info"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.LoadedWalletActivity"
android:label="@string/title_activity_loaded_wallet"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.VerifyCardActivity"
android:label="@string/title_activity_loaded_wallet"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.CreateNewWalletActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.PreparePaymentActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.ConfirmPaymentActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.SignPaymentActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.PurgeActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.SwapPINActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.QRScanActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.SendTransactionActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.tangem.presentation.activity.SettingsFeatureActivity"
android:label="@string/title_activity_settings_feature">
</activity>
</application>

View file

@ -1,90 +0,0 @@
package com.tangem.presentation.activity
import android.content.res.Configuration
import android.os.Bundle
import android.preference.PreferenceActivity
import android.support.annotation.LayoutRes
import android.support.v7.app.ActionBar
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.Toolbar
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
/**
* A [android.preference.PreferenceActivity] which implements and proxies the necessary calls
* to be used with AppCompat.
*/
abstract class AppCompatPreferenceActivity : PreferenceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
delegate.installViewFactory()
delegate.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
delegate.onPostCreate(savedInstanceState)
}
val supportActionBar: ActionBar?
get() = delegate.supportActionBar
fun setSupportActionBar(toolbar: Toolbar?) {
delegate.setSupportActionBar(toolbar)
}
override fun getMenuInflater(): MenuInflater {
return delegate.menuInflater
}
override fun setContentView(@LayoutRes layoutResID: Int) {
delegate.setContentView(layoutResID)
}
override fun setContentView(view: View) {
delegate.setContentView(view)
}
override fun setContentView(view: View, params: ViewGroup.LayoutParams) {
delegate.setContentView(view, params)
}
override fun addContentView(view: View, params: ViewGroup.LayoutParams) {
delegate.addContentView(view, params)
}
override fun onPostResume() {
super.onPostResume()
delegate.onPostResume()
}
override fun onTitleChanged(title: CharSequence, color: Int) {
super.onTitleChanged(title, color)
delegate.setTitle(title)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
delegate.onConfigurationChanged(newConfig)
}
override fun onStop() {
super.onStop()
delegate.onStop()
}
override fun onDestroy() {
super.onDestroy()
delegate.onDestroy()
}
override fun invalidateOptionsMenu() {
delegate.invalidateOptionsMenu()
}
private val delegate: AppCompatDelegate by lazy {
AppCompatDelegate.create(this, null)
}
}

View file

@ -1,126 +0,0 @@
package com.tangem.presentation.activity;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import com.tangem.domain.wallet.TangemCard;
import com.tangem.presentation.fragment.WalletInfo;
import com.tangem.wallet.R;
public class CardInfoActivity extends AppCompatActivity implements WalletInfo.OnFragmentInteractionListener {
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
private TangemCard mCard;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_info);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
String UID = getIntent().getStringExtra("UID");
mCard = new TangemCard(UID);
mCard.LoadFromBundle(getIntent().getBundleExtra("Card"));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_card_info, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
if (position == 0) {
return WalletInfo.newInstance(mCard);
} /*else if (position == 1) {
return WalletUnspentFragment.newInstance(mCard);
} else if (position == 2) {
return WalletHistoryFragment.newInstance(mCard);
}*/
return null;
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Wallet info";
case 1:
return "Unspent";
case 2:
return "History";
}
return null;
}
}
}

View file

@ -23,24 +23,24 @@ import android.widget.TextView;
import android.widget.Toast;
import com.tangem.data.network.request.ElectrumRequest;
import com.tangem.data.network.request.FeeRequest;
import com.tangem.data.network.request.InfuraRequest;
import com.tangem.data.network.task.ElectrumTask;
import com.tangem.data.network.task.FeeTask;
import com.tangem.data.network.task.InfuraTask;
import com.tangem.domain.cardReader.NfcManager;
import com.tangem.domain.wallet.TangemCard;
import com.tangem.util.Util;
import com.tangem.util.BTCUtils;
import com.tangem.domain.wallet.Blockchain;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.CoinEngineFactory;
import com.tangem.util.DerEncodingUtil;
import com.tangem.data.network.task.ElectrumTask;
import com.tangem.data.network.request.FeeRequest;
import com.tangem.data.network.task.FeeTask;
import com.tangem.util.FormatUtil;
import com.tangem.data.network.request.InfuraRequest;
import com.tangem.data.network.task.InfuraTask;
import com.tangem.wallet.R;
import com.tangem.domain.wallet.SharedData;
import com.tangem.domain.wallet.TangemCard;
import com.tangem.domain.wallet.Transaction;
import com.tangem.domain.wallet.UnspentOutputInfo;
import com.tangem.util.BTCUtils;
import com.tangem.util.DerEncodingUtil;
import com.tangem.util.FormatUtil;
import com.tangem.util.Util;
import com.tangem.wallet.R;
import org.json.JSONException;
@ -57,392 +57,31 @@ public class ConfirmPaymentActivity extends AppCompatActivity implements NfcAdap
private static final int REQUEST_CODE_SIGN_PAYMENT = 1;
private static final int REQUEST_CODE_REQUEST_PIN2 = 2;
Button btnSend;
boolean feeRequestSuccess = false;
boolean balanceRequestSuccess = false;
EditText etWallet;
TextView tvCardID, tvBalance, tvCurrency, tvCurrency2, tvBalanceEquivalent, tvAmountEquivalent, tvFeeEquivalent;
EditText etAmount;
EditText etFee;
ImageView ivCamera;
TangemCard mCard;
RadioGroup rgFee;
String minFee = null, maxFee = null, normalFee = null;
Long minFeeInInternalUnits = 0L;
private Button btnSend;
private boolean feeRequestSuccess = false;
private boolean balanceRequestSuccess = false;
private EditText etWallet;
private TextView tvAmountEquivalent;
private TextView tvFeeEquivalent;
private EditText etAmount;
private EditText etFee;
private ImageView ivCamera;
private TangemCard mCard;
private RadioGroup rgFee;
private String minFee = null, maxFee = null, normalFee = null;
private Long minFeeInInternalUnits = 0L;
private NfcManager mNfcManager;
int requestPIN2Count = 0;
ProgressBar progressBar;
boolean nodeCheck = false;
Date dtVerifyed = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_confirm_payment);
MainActivity.commonInit(getApplicationContext());
mNfcManager = new NfcManager(this, this);
mCard = new TangemCard(getIntent().getStringExtra("UID"));
mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card"));
progressBar = findViewById(R.id.progressBar);
btnSend = findViewById(R.id.btnSend);
etWallet = findViewById(R.id.etWallet);
tvCardID = findViewById(R.id.tvCardID);
tvBalance = findViewById(R.id.tvBalance);
tvCurrency = findViewById(R.id.tvCurrency);
tvCurrency2 = findViewById(R.id.tvCurrency2);
etAmount = findViewById(R.id.etAmount);
etFee = findViewById(R.id.etFee);
tvBalanceEquivalent = findViewById(R.id.tvBalanceEquivalent);
tvAmountEquivalent = findViewById(R.id.tvAmountEquivalent);
tvFeeEquivalent = findViewById(R.id.tvFeeEquivalent);
ivCamera = findViewById(R.id.ivCamera);
rgFee = findViewById(R.id.rgFee);
rgFee.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
doSetFee(checkedId);
}
});
etAmount.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
tvAmountEquivalent.setText(engine.GetAmountEqualentDescriptor(mCard, etAmount.getText().toString()));
if (!mCard.getAmountEquivalentDescriptionAvailable()) {
tvAmountEquivalent.setError("Service unavailable");
} else {
tvAmountEquivalent.setError(null);
}
} catch (Exception e) {
e.printStackTrace();
tvAmountEquivalent.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
etFee.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
String eqFee = engine.EvaluteFeeEquivalent(mCard, etFee.getText().toString());
tvFeeEquivalent.setText(eqFee);
if (!mCard.getAmountEquivalentDescriptionAvailable()) {
tvFeeEquivalent.setError("Service unavailable");
} else {
tvFeeEquivalent.setError(null);
}
} catch (Exception e) {
e.printStackTrace();
tvFeeEquivalent.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
//tvBalance.setText(engine.GetBalanceWithAlter(mCard));
if (mCard.getBlockchain() == Blockchain.Token) {
Spanned html = Html.fromHtml(engine.GetBalanceWithAlter(mCard));
tvBalance.setText(html);
} else {
tvBalance.setText(engine.GetBalanceWithAlter(mCard));
}
etAmount.setText(getIntent().getStringExtra("Amount"));
tvCurrency.setText(engine.GetBalanceCurrency(mCard));
tvCurrency2.setText(engine.GetFeeCurrency());
tvCardID.setText(mCard.getCIDDescription());
//tvBalanceEquivalent.setText(mCard.getBalanceEquivalentDescription());
tvBalanceEquivalent.setText(engine.GetBalanceEquivalent(mCard));
if (!mCard.getAmountEquivalentDescriptionAvailable()) {
tvBalanceEquivalent.setError("Service unavailable");
} else {
tvBalanceEquivalent.setError(null);
}
etWallet.setText(getIntent().getStringExtra("Wallet"));
etFee.setText("?");
btnSend.setVisibility(View.INVISIBLE);
feeRequestSuccess = false;
balanceRequestSuccess = false;
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -1);
if (dtVerifyed == null || dtVerifyed.before(calendar.getTime())) {
FinishActivityWithError(Activity.RESULT_CANCELED, "The obtained data is outdated! Try again");
return;
}
CoinEngine engineCoin = CoinEngineFactory.Create(mCard.getBlockchain());
if (engineCoin.IsNeedCheckNode() && !nodeCheck) {
Toast.makeText(getBaseContext(), "Cannot reach current active blockchain node. Try again", Toast.LENGTH_LONG).show();
return;
}
String txFee = etFee.getText().toString();
String txAmount = etAmount.getText().toString();
if (!engineCoin.HasBalanceInfo(mCard)) {
FinishActivityWithError(Activity.RESULT_CANCELED, "Cannot check balance! No connection with blockchain nodes");
return;
} else if (!engineCoin.IsBalanceNotZero(mCard)) {
FinishActivityWithError(Activity.RESULT_CANCELED, "The wallet is empty");
return;
} else if (!engineCoin.CheckUnspentTransaction(mCard)) {
//else if (mCard.getUnspentTransactions().size() == 0 && mCard.getBlockchain() != Blockchain.Ethereum) {
FinishActivityWithError(Activity.RESULT_CANCELED, "Please wait for confirmation of incoming transaction");
return;
}
if (!engineCoin.CheckAmountValie(mCard, txAmount, txFee, minFeeInInternalUnits)) {
FinishActivityWithError(Activity.RESULT_CANCELED, "Fee exceeds payment amount. Enter correct value and repeat sending.");
return;
}
requestPIN2Count = 0;
Intent intent = new Intent(getBaseContext(), RequestPINActivity.class);
intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString());
intent.putExtra("UID", mCard.getUID());
intent.putExtra("Card", mCard.getAsBundle());
startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2);
}
});
if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) {
ETHRequestTask task = new ETHRequestTask(mCard.getBlockchain());
InfuraRequest req = InfuraRequest.GetGasPrise(mCard.getWallet());
req.setID(67);
req.setBlockchain(mCard.getBlockchain());
rgFee.setEnabled(false);
task.execute(req);
} else {
rgFee.setEnabled(true);
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
CoinEngine engineCoin = CoinEngineFactory.Create(mCard.getBlockchain());
for (int i = 0; i < data.allRequest; ++i) {
String nodeAddress = engineCoin.GetNextNode(mCard);
int nodePort = engineCoin.GetNextNodePort(mCard);
//ConnectTask connectTaskEx = new ConnectTask(Blockchain.getNextServiceHost(mCard), Blockchain.getNextServicePort(mCard), data);
ConnectTask connectTaskEx = new ConnectTask(nodeAddress, nodePort, data);
//connectTaskEx.execute(ElectrumRequest.CheckBalance(mCard.getWallet()));
connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ElectrumRequest.CheckBalance(mCard.getWallet()));
}
String nodeAddress = engineCoin.GetNode(mCard);
int nodePort = engineCoin.GetNodePort(mCard);
ConnectTask connectTask = new ConnectTask(nodeAddress, nodePort, data);
//ConnectTask connectTask = new ConnectTask(Blockchain.getServiceHost(mCard), Blockchain.getServicePort(mCard));
connectTask.execute(/*ElectrumRequest.CheckBalance(mCard.getWallet()), */ElectrumRequest.GetFee(mCard.getWallet()));
int calcSize = 256;
try {
calcSize = BuildSize(etWallet.getText().toString(), "0.00", etAmount.getText().toString());
} catch (Exception ex) {
Log.e("Build Fee error", ex.getMessage());
}
SharedData sharedFee = new SharedData(SharedData.COUNT_REQUEST);
progressBar.setVisibility(View.VISIBLE);
for (int i = 0; i < SharedData.COUNT_REQUEST; ++i) {
ConnectFeeTask feeTask = new ConnectFeeTask(sharedFee);
feeTask.execute(FeeRequest.GetFee(mCard.getWallet(), calcSize, FeeRequest.NORMAL),
FeeRequest.GetFee(mCard.getWallet(), calcSize, FeeRequest.MINIMAL),
FeeRequest.GetFee(mCard.getWallet(), calcSize, FeeRequest.PRIORITY));
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
Intent intent = new Intent();
intent.putExtra("message", "Operation canceled");
setResult(Activity.RESULT_CANCELED, intent);
finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SIGN_PAYMENT) {
if (data != null && data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) {
TangemCard updatedCard = new TangemCard(data.getStringExtra("UID"));
updatedCard.LoadFromBundle(data.getBundleExtra("Card"));
mCard = updatedCard;
}
if (resultCode == SignPaymentActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++;
Intent intent = new Intent(getBaseContext(), RequestPINActivity.class);
intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString());
intent.putExtra("UID", mCard.getUID());
intent.putExtra("Card", mCard.getAsBundle());
startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2);
return;
}
setResult(resultCode, data);
finish();
} else if (requestCode == REQUEST_CODE_REQUEST_PIN2) {
if (resultCode == Activity.RESULT_OK) {
Intent intent = new Intent(getBaseContext(), SignPaymentActivity.class);
intent.putExtra("UID", mCard.getUID());
intent.putExtra("Card", mCard.getAsBundle());
intent.putExtra("Wallet", etWallet.getText().toString());
intent.putExtra("Amount", etAmount.getText().toString());
intent.putExtra("Fee", etFee.getText().toString());
startActivityForResult(intent, REQUEST_CODE_SIGN_PAYMENT);
} else {
Toast.makeText(getBaseContext(), "PIN2 is required to sign the payment", Toast.LENGTH_LONG).show();
}
}
}
void FinishActivityWithError(int errorCode, String message) {
//Snackbar.make(etFee, message, Snackbar.LENGTH_LONG).show();
Intent intent = new Intent();
intent.putExtra("message", message);
setResult(errorCode, intent);
finish();
}
@Override
public void onTagDiscovered(Tag tag) {
try {
Log.w(getClass().getName(), "Ignore discovered tag!");
mNfcManager.ignoreTag(tag);
} catch (IOException e) {
e.printStackTrace();
}
}
int BuildSize(String outputAddress, String outFee, String outAmount) throws Exception {
String myAddress = mCard.getWallet();
String changeAddress = myAddress; //"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi";
byte[] pbKey = mCard.getWalletPublicKey();
byte[] pbComprKey = mCard.getWalletPublicKeyRar();
// Build script for our address
List<TangemCard.UnspentTransaction> rawTxList = mCard.getUnspentTransactions();
byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
// Collect unspent
ArrayList<UnspentOutputInfo> unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
long fullAmount = 0;
for (int i = 0; i < unspentOutputs.size(); ++i) {
fullAmount += unspentOutputs.get(i).value;
}
// Get first unspent
UnspentOutputInfo outPut = unspentOutputs.get(0);
int outPutIndex = outPut.outputIndex;
// get prev TX id;
String prevTXID = rawTxList.get(0).txID;//"f67b838d6e2c0c587f476f583843e93ff20368eaf96a798bdc25e01f53f8f5d2";
long fees = FormatUtil.ConvertStringToLong(outFee);
long amount = FormatUtil.ConvertStringToLong(outAmount);
amount = amount - fees;
long change = fullAmount - fees - amount;
if (amount + fees > fullAmount) {
throw new Exception(String.format("Balance (%d) < amount (%d) + (%d)", fullAmount, change, amount));
}
byte[][] hashesForSign = new byte[unspentOutputs.size()][];
for (int i = 0; i < unspentOutputs.size(); ++i) {
byte[] newTX = BTCUtils.buildTXForSign(myAddress, outputAddress, changeAddress, unspentOutputs, i, amount, change);
byte[] hashData = Util.calculateSHA256(newTX);
byte[] doubleHashData = Util.calculateSHA256(hashData);
Log.e("TX_BODY_1", BTCUtils.toHex(newTX));
Log.e("TX_HASH_1", BTCUtils.toHex(hashData));
Log.e("TX_HASH_2", BTCUtils.toHex(doubleHashData));
unspentOutputs.get(i).bodyDoubleHash = doubleHashData;
unspentOutputs.get(i).bodyHash = hashData;
hashesForSign[i] = doubleHashData;
}
byte[] signFromCard = new byte[64 * unspentOutputs.size()];
for (int i = 0; i < unspentOutputs.size(); ++i) {
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0 + i * 64, 32 + i * 64));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32 + i * 64, 64 + i * 64));
byte[] encodingSign = DerEncodingUtil.packSignDer(r, s, pbKey);
unspentOutputs.get(i).scriptForBuild = encodingSign;
}
byte[] realTX = BTCUtils.buildTXForSend(outputAddress, changeAddress, unspentOutputs, amount, change);
return realTX.length;
}
private int requestPIN2Count = 0;
private ProgressBar progressBar;
private boolean nodeCheck = false;
private Date dtVerifyed = null;
private class ConnectTask extends ElectrumTask {
public ConnectTask(String host, int port) {
super(host, port);
}
public ConnectTask(String host, int port, SharedData sharedData) {
ConnectTask(String host, int port, SharedData sharedData) {
super(host, port, sharedData);
}
@ -588,7 +227,7 @@ public class ConfirmPaymentActivity extends AppCompatActivity implements NfcAdap
}
private class ConnectFeeTask extends FeeTask {
public ConnectFeeTask(SharedData sharedData) {
ConnectFeeTask(SharedData sharedData) {
super(sharedData);
}
@ -598,9 +237,7 @@ public class ConfirmPaymentActivity extends AppCompatActivity implements NfcAdap
for (FeeRequest request : requests) {
if (request.error == null) {
long minFeeRate = 0;
try {
try {
String tmpAnswer = request.getAsString();
BigDecimal minFeeBD = new BigDecimal(tmpAnswer);
@ -696,20 +333,219 @@ public class ConfirmPaymentActivity extends AppCompatActivity implements NfcAdap
}
}
private void doSetFee(int checkedRadioButtonId) {
switch (checkedRadioButtonId) {
case R.id.rbMinimalFee:
if (minFee != null) etFee.setText(minFee);
else etFee.setText("?");
break;
case R.id.rbNormalFee:
if (normalFee != null) etFee.setText(normalFee);
else etFee.setText("?");
break;
case R.id.rbMaximumFee:
if (maxFee != null) etFee.setText(maxFee);
else etFee.setText("?");
break;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_confirm_payment);
MainActivity.commonInit(getApplicationContext());
mNfcManager = new NfcManager(this, this);
mCard = new TangemCard(getIntent().getStringExtra("UID"));
mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card"));
progressBar = findViewById(R.id.progressBar);
btnSend = findViewById(R.id.btnSend);
etWallet = findViewById(R.id.etWallet);
TextView tvCardID = findViewById(R.id.tvCardID);
TextView tvBalance = findViewById(R.id.tvBalance);
TextView tvCurrency = findViewById(R.id.tvCurrency);
TextView tvCurrency2 = findViewById(R.id.tvCurrency2);
etAmount = findViewById(R.id.etAmount);
etFee = findViewById(R.id.etFee);
TextView tvBalanceEquivalent = findViewById(R.id.tvBalanceEquivalent);
tvAmountEquivalent = findViewById(R.id.tvAmountEquivalent);
tvFeeEquivalent = findViewById(R.id.tvFeeEquivalent);
ivCamera = findViewById(R.id.ivCamera);
rgFee = findViewById(R.id.rgFee);
rgFee.setOnCheckedChangeListener((group, checkedId) -> doSetFee(checkedId));
etAmount.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
tvAmountEquivalent.setText(engine.GetAmountEqualentDescriptor(mCard, etAmount.getText().toString()));
if (!mCard.getAmountEquivalentDescriptionAvailable()) {
tvAmountEquivalent.setError("Service unavailable");
} else {
tvAmountEquivalent.setError(null);
}
} catch (Exception e) {
e.printStackTrace();
tvAmountEquivalent.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
etFee.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
String eqFee = engine.EvaluteFeeEquivalent(mCard, etFee.getText().toString());
tvFeeEquivalent.setText(eqFee);
if (!mCard.getAmountEquivalentDescriptionAvailable()) {
tvFeeEquivalent.setError("Service unavailable");
} else {
tvFeeEquivalent.setError(null);
}
} catch (Exception e) {
e.printStackTrace();
tvFeeEquivalent.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
//tvBalance.setText(engine.GetBalanceWithAlter(mCard));
if (mCard.getBlockchain() == Blockchain.Token) {
Spanned html = Html.fromHtml(engine.GetBalanceWithAlter(mCard));
tvBalance.setText(html);
} else {
tvBalance.setText(engine.GetBalanceWithAlter(mCard));
}
etAmount.setText(getIntent().getStringExtra("Amount"));
tvCurrency.setText(engine.GetBalanceCurrency(mCard));
tvCurrency2.setText(engine.GetFeeCurrency());
tvCardID.setText(mCard.getCIDDescription());
//tvBalanceEquivalent.setText(mCard.getBalanceEquivalentDescription());
tvBalanceEquivalent.setText(engine.GetBalanceEquivalent(mCard));
if (!mCard.getAmountEquivalentDescriptionAvailable()) {
tvBalanceEquivalent.setError("Service unavailable");
} else {
tvBalanceEquivalent.setError(null);
}
etWallet.setText(getIntent().getStringExtra("Wallet"));
etFee.setText("?");
btnSend.setVisibility(View.INVISIBLE);
feeRequestSuccess = false;
balanceRequestSuccess = false;
btnSend.setOnClickListener(v -> {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -1);
if (dtVerifyed == null || dtVerifyed.before(calendar.getTime())) {
FinishActivityWithError(Activity.RESULT_CANCELED, "The obtained data is outdated! Try again");
return;
}
CoinEngine engineCoin = CoinEngineFactory.Create(mCard.getBlockchain());
if (engineCoin.IsNeedCheckNode() && !nodeCheck) {
Toast.makeText(getBaseContext(), "Cannot reach current active blockchain node. Try again", Toast.LENGTH_LONG).show();
return;
}
String txFee = etFee.getText().toString();
String txAmount = etAmount.getText().toString();
if (!engineCoin.HasBalanceInfo(mCard)) {
FinishActivityWithError(Activity.RESULT_CANCELED, "Cannot check balance! No connection with blockchain nodes");
return;
} else if (!engineCoin.IsBalanceNotZero(mCard)) {
FinishActivityWithError(Activity.RESULT_CANCELED, "The wallet is empty");
return;
} else if (!engineCoin.CheckUnspentTransaction(mCard)) {
//else if (mCard.getUnspentTransactions().size() == 0 && mCard.getBlockchain() != Blockchain.Ethereum) {
FinishActivityWithError(Activity.RESULT_CANCELED, "Please wait for confirmation of incoming transaction");
return;
}
if (!engineCoin.CheckAmountValie(mCard, txAmount, txFee, minFeeInInternalUnits)) {
FinishActivityWithError(Activity.RESULT_CANCELED, "Fee exceeds payment amount. Enter correct value and repeat sending.");
return;
}
requestPIN2Count = 0;
Intent intent = new Intent(getBaseContext(), RequestPINActivity.class);
intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString());
intent.putExtra("UID", mCard.getUID());
intent.putExtra("Card", mCard.getAsBundle());
startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2);
});
if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) {
ETHRequestTask task = new ETHRequestTask(mCard.getBlockchain());
InfuraRequest req = InfuraRequest.GetGasPrise(mCard.getWallet());
req.setID(67);
req.setBlockchain(mCard.getBlockchain());
rgFee.setEnabled(false);
task.execute(req);
} else {
rgFee.setEnabled(true);
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
CoinEngine engineCoin = CoinEngineFactory.Create(mCard.getBlockchain());
for (int i = 0; i < data.allRequest; ++i) {
String nodeAddress = engineCoin.GetNextNode(mCard);
int nodePort = engineCoin.GetNextNodePort(mCard);
//ConnectTask connectTaskEx = new ConnectTask(Blockchain.getNextServiceHost(mCard), Blockchain.getNextServicePort(mCard), data);
ConnectTask connectTaskEx = new ConnectTask(nodeAddress, nodePort, data);
//connectTaskEx.execute(ElectrumRequest.CheckBalance(mCard.getWallet()));
connectTaskEx.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ElectrumRequest.CheckBalance(mCard.getWallet()));
}
String nodeAddress = engineCoin.GetNode(mCard);
int nodePort = engineCoin.GetNodePort(mCard);
ConnectTask connectTask = new ConnectTask(nodeAddress, nodePort, data);
//ConnectTask connectTask = new ConnectTask(Blockchain.getServiceHost(mCard), Blockchain.getServicePort(mCard));
connectTask.execute(/*ElectrumRequest.CheckBalance(mCard.getWallet()), */ElectrumRequest.GetFee(mCard.getWallet()));
int calcSize = 256;
try {
calcSize = BuildSize(etWallet.getText().toString(), "0.00", etAmount.getText().toString());
} catch (Exception ex) {
Log.e("Build Fee error", ex.getMessage());
}
SharedData sharedFee = new SharedData(SharedData.COUNT_REQUEST);
progressBar.setVisibility(View.VISIBLE);
for (int i = 0; i < SharedData.COUNT_REQUEST; ++i) {
ConnectFeeTask feeTask = new ConnectFeeTask(sharedFee);
feeTask.execute(FeeRequest.GetFee(mCard.getWallet(), calcSize, FeeRequest.NORMAL),
FeeRequest.GetFee(mCard.getWallet(), calcSize, FeeRequest.MINIMAL),
FeeRequest.GetFee(mCard.getWallet(), calcSize, FeeRequest.PRIORITY));
}
}
}
@ -730,4 +566,155 @@ public class ConfirmPaymentActivity extends AppCompatActivity implements NfcAdap
super.onStop();
mNfcManager.onStop();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SIGN_PAYMENT) {
if (data != null && data.getExtras().containsKey("UID") && data.getExtras().containsKey("Card")) {
TangemCard updatedCard = new TangemCard(data.getStringExtra("UID"));
updatedCard.LoadFromBundle(data.getBundleExtra("Card"));
mCard = updatedCard;
}
if (resultCode == SignPaymentActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
requestPIN2Count++;
Intent intent = new Intent(getBaseContext(), RequestPINActivity.class);
intent.putExtra("mode", RequestPINActivity.Mode.RequestPIN2.toString());
intent.putExtra("UID", mCard.getUID());
intent.putExtra("Card", mCard.getAsBundle());
startActivityForResult(intent, REQUEST_CODE_REQUEST_PIN2);
return;
}
setResult(resultCode, data);
finish();
} else if (requestCode == REQUEST_CODE_REQUEST_PIN2) {
if (resultCode == Activity.RESULT_OK) {
Intent intent = new Intent(getBaseContext(), SignPaymentActivity.class);
intent.putExtra("UID", mCard.getUID());
intent.putExtra("Card", mCard.getAsBundle());
intent.putExtra("Wallet", etWallet.getText().toString());
intent.putExtra("Amount", etAmount.getText().toString());
intent.putExtra("Fee", etFee.getText().toString());
startActivityForResult(intent, REQUEST_CODE_SIGN_PAYMENT);
} else {
Toast.makeText(getBaseContext(), "PIN2 is required to sign the payment", Toast.LENGTH_LONG).show();
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
Intent intent = new Intent();
intent.putExtra("message", "Operation canceled");
setResult(Activity.RESULT_CANCELED, intent);
finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
void FinishActivityWithError(int errorCode, String message) {
//Snackbar.make(etFee, message, Snackbar.LENGTH_LONG).show();
Intent intent = new Intent();
intent.putExtra("message", message);
setResult(errorCode, intent);
finish();
}
@Override
public void onTagDiscovered(Tag tag) {
try {
Log.w(getClass().getName(), "Ignore discovered tag!");
mNfcManager.ignoreTag(tag);
} catch (IOException e) {
e.printStackTrace();
}
}
int BuildSize(String outputAddress, String outFee, String outAmount) throws Exception {
String myAddress = mCard.getWallet();
String changeAddress = myAddress; //"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi";
byte[] pbKey = mCard.getWalletPublicKey();
byte[] pbComprKey = mCard.getWalletPublicKeyRar();
// Build script for our address
List<TangemCard.UnspentTransaction> rawTxList = mCard.getUnspentTransactions();
byte[] outputScriptWeAreAbleToSpend = Transaction.Script.buildOutput(myAddress).bytes;
// Collect unspent
ArrayList<UnspentOutputInfo> unspentOutputs = BTCUtils.getOutputs(rawTxList, outputScriptWeAreAbleToSpend);
long fullAmount = 0;
for (int i = 0; i < unspentOutputs.size(); ++i) {
fullAmount += unspentOutputs.get(i).value;
}
// Get first unspent
UnspentOutputInfo outPut = unspentOutputs.get(0);
int outPutIndex = outPut.outputIndex;
// get prev TX id;
String prevTXID = rawTxList.get(0).txID;//"f67b838d6e2c0c587f476f583843e93ff20368eaf96a798bdc25e01f53f8f5d2";
long fees = FormatUtil.ConvertStringToLong(outFee);
long amount = FormatUtil.ConvertStringToLong(outAmount);
amount = amount - fees;
long change = fullAmount - fees - amount;
if (amount + fees > fullAmount) {
throw new Exception(String.format("Balance (%d) < amount (%d) + (%d)", fullAmount, change, amount));
}
byte[][] hashesForSign = new byte[unspentOutputs.size()][];
for (int i = 0; i < unspentOutputs.size(); ++i) {
byte[] newTX = BTCUtils.buildTXForSign(myAddress, outputAddress, changeAddress, unspentOutputs, i, amount, change);
byte[] hashData = Util.calculateSHA256(newTX);
byte[] doubleHashData = Util.calculateSHA256(hashData);
Log.e("TX_BODY_1", BTCUtils.toHex(newTX));
Log.e("TX_HASH_1", BTCUtils.toHex(hashData));
Log.e("TX_HASH_2", BTCUtils.toHex(doubleHashData));
unspentOutputs.get(i).bodyDoubleHash = doubleHashData;
unspentOutputs.get(i).bodyHash = hashData;
hashesForSign[i] = doubleHashData;
}
byte[] signFromCard = new byte[64 * unspentOutputs.size()];
for (int i = 0; i < unspentOutputs.size(); ++i) {
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signFromCard, 0 + i * 64, 32 + i * 64));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32 + i * 64, 64 + i * 64));
byte[] encodingSign = DerEncodingUtil.packSignDer(r, s, pbKey);
unspentOutputs.get(i).scriptForBuild = encodingSign;
}
byte[] realTX = BTCUtils.buildTXForSend(outputAddress, changeAddress, unspentOutputs, amount, change);
return realTX.length;
}
private void doSetFee(int checkedRadioButtonId) {
switch (checkedRadioButtonId) {
case R.id.rbMinimalFee:
if (minFee != null) etFee.setText(minFee);
else etFee.setText("?");
break;
case R.id.rbNormalFee:
if (normalFee != null) etFee.setText(normalFee);
else etFee.setText("?");
break;
case R.id.rbMaximumFee:
if (maxFee != null) etFee.setText(maxFee);
else etFee.setText("?");
break;
}
}
}

View file

@ -25,100 +25,20 @@ import com.tangem.wallet.R;
import com.tangem.presentation.dialog.WaitSecurityDelayDialog;
public class CreateNewWalletActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, CardProtocol.Notifications {
public static final String TAG = CreateNewWalletActivity.class.getSimpleName();
public static final int RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER;
private TangemCard mCard;
private TextView tvCardID;
private NfcManager mNfcManager;
private static final String logTag = "CreateNewActivity";
private ProgressBar progressBar;
private CreateNewWalletTask createNewWalletTask;
private boolean lastReadSuccess = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_new_wallet);
MainActivity.commonInit(getApplicationContext());
mCard = new TangemCard(getIntent().getStringExtra("UID"));
mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card"));
tvCardID = findViewById(R.id.tvCardID);
tvCardID.setText(mCard.getCIDDescription());
mNfcManager = new NfcManager(this, this);
progressBar = findViewById(R.id.progressBar);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY));
progressBar.setVisibility(View.INVISIBLE);
}
@Override
public void onTagDiscovered(Tag tag) {
try {
// get IsoDep handle and run cardReader thread
final IsoDep isoDep = IsoDep.get(tag);
if (isoDep == null) {
throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err));
}
byte UID[] = tag.getId();
String sUID = Util.byteArrayToHexString(UID);
Log.v(logTag, "UID: " + sUID);
if (sUID.equals(mCard.getUID())) {
if (lastReadSuccess) {
isoDep.setTimeout(mCard.getPauseBeforePIN2() + 5000);
} else {
isoDep.setTimeout(mCard.getPauseBeforePIN2() + 65000);
}
createNewWalletTask = new CreateNewWalletTask(isoDep, this);
createNewWalletTask.start();
} else {
Log.d(logTag, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")");
mNfcManager.ignoreTag(isoDep.getTag());
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onResume() {
super.onResume();
mNfcManager.onResume();
}
@Override
public void onPause() {
mNfcManager.onPause();
if (createNewWalletTask != null) {
createNewWalletTask.cancel(true);
}
super.onPause();
}
@Override
public void onStop() {
// dismiss enable NFC dialog
mNfcManager.onStop();
if (createNewWalletTask != null) {
createNewWalletTask.cancel(true);
}
super.onStop();
}
// @Override
// public Dialog CreateNFCDialog(int id, AlertDialogWrapper.Builder builder, LayoutInflater li) {
// return mNfcManager.ShowNFCEnableDialog(); //onCreateDialog(id, builder, li);
// }
private class CreateNewWalletTask extends Thread {
IsoDep mIsoDep;
CardProtocol.Notifications mNotifications;
private IsoDep mIsoDep;
private CardProtocol.Notifications mNotifications;
private boolean isCancelled = false;
public CreateNewWalletTask(IsoDep isoDep, CardProtocol.Notifications notifications) {
@ -198,13 +118,85 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
}
public void OnReadStart(CardProtocol cardProtocol) {
progressBar.post(new Runnable() {
@Override
public void run() {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_new_wallet);
MainActivity.commonInit(getApplicationContext());
mCard = new TangemCard(getIntent().getStringExtra("UID"));
mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card"));
TextView tvCardID = findViewById(R.id.tvCardID);
tvCardID.setText(mCard.getCIDDescription());
mNfcManager = new NfcManager(this, this);
progressBar = findViewById(R.id.progressBar);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY));
progressBar.setVisibility(View.INVISIBLE);
}
@Override
public void onTagDiscovered(Tag tag) {
try {
// get IsoDep handle and run cardReader thread
final IsoDep isoDep = IsoDep.get(tag);
if (isoDep == null) {
throw new CardProtocol.TangemException(getString(R.string.wrong_tag_err));
}
byte UID[] = tag.getId();
String sUID = Util.byteArrayToHexString(UID);
Log.v(TAG, "UID: " + sUID);
if (sUID.equals(mCard.getUID())) {
if (lastReadSuccess) {
isoDep.setTimeout(mCard.getPauseBeforePIN2() + 5000);
} else {
isoDep.setTimeout(mCard.getPauseBeforePIN2() + 65000);
}
createNewWalletTask = new CreateNewWalletTask(isoDep, this);
createNewWalletTask.start();
} else {
Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")");
mNfcManager.ignoreTag(isoDep.getTag());
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onResume() {
super.onResume();
mNfcManager.onResume();
}
@Override
public void onPause() {
mNfcManager.onPause();
if (createNewWalletTask != null) {
createNewWalletTask.cancel(true);
}
super.onPause();
}
@Override
public void onStop() {
// dismiss enable NFC dialog
mNfcManager.onStop();
if (createNewWalletTask != null) {
createNewWalletTask.cancel(true);
}
super.onStop();
}
public void OnReadStart(CardProtocol cardProtocol) {
progressBar.post(() -> {
progressBar.setVisibility(View.VISIBLE);
progressBar.setProgress(5);
}
});
}
@ -214,9 +206,7 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
if (cardProtocol != null) {
if (cardProtocol.getError() == null) {
progressBar.post(new Runnable() {
@Override
public void run() {
progressBar.post(() -> {
progressBar.setProgress(100);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN));
Intent intent = new Intent();
@ -224,21 +214,15 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
intent.putExtra("Card", cardProtocol.getCard().getAsBundle());
setResult(Activity.RESULT_OK, intent);
finish();
}
});
} else {
lastReadSuccess = false;
if (cardProtocol.getError() instanceof CardProtocol.TangemException_InvalidPIN) {
progressBar.post(new Runnable() {
@Override
public void run() {
progressBar.post(() -> {
progressBar.setProgress(100);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED));
}
});
progressBar.postDelayed(new Runnable() {
@Override
public void run() {
progressBar.postDelayed(() -> {
try {
progressBar.setProgress(0);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY));
@ -252,32 +236,25 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
} catch (Exception e) {
e.printStackTrace();
}
}
}, 500);
return;
} else {
progressBar.post(new Runnable() {
@Override
public void run() {
progressBar.post(() -> {
if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) {
if (!NoExtendedLengthSupportDialog.allreadyShowed) {
new NoExtendedLengthSupportDialog().show(getFragmentManager(), "NoExtendedLengthSupportDialog");
new NoExtendedLengthSupportDialog().show(getFragmentManager(), NoExtendedLengthSupportDialog.TAG);
}
} else {
Toast.makeText(getBaseContext(), "Try to scan again", Toast.LENGTH_LONG).show();
Toast.makeText(getBaseContext(), R.string.try_to_scan_again, Toast.LENGTH_LONG).show();
}
progressBar.setProgress(100);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED));
}
});
}
}
}
progressBar.postDelayed(new Runnable() {
@Override
public void run() {
progressBar.postDelayed(() -> {
try {
progressBar.setProgress(0);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY));
@ -285,26 +262,18 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
} catch (Exception e) {
e.printStackTrace();
}
}
}, 500);
}
public void OnReadProgress(CardProtocol protocol, final int progress) {
progressBar.post(new Runnable() {
@Override
public void run() {
progressBar.setProgress(progress);
}
});
progressBar.post(() -> progressBar.setProgress(progress));
}
public void OnReadCancel() {
createNewWalletTask = null;
progressBar.postDelayed(new Runnable() {
@Override
public void run() {
progressBar.postDelayed(() -> {
try {
progressBar.setProgress(0);
progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY));
@ -312,7 +281,6 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
} catch (Exception e) {
e.printStackTrace();
}
}
}, 500);
}
@ -330,5 +298,5 @@ public class CreateNewWalletActivity extends AppCompatActivity implements NfcAda
public void OnReadAfterRequest() {
WaitSecurityDelayDialog.onReadAfterRequest(this);
}
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.presentation.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
@ -11,7 +12,6 @@ import android.text.Html;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
@ -21,26 +21,25 @@ import com.tangem.domain.cardReader.NfcManager;
import com.tangem.domain.wallet.Blockchain;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.CoinEngineFactory;
import com.tangem.util.FormatUtil;
import com.tangem.domain.wallet.TangemCard;
import com.tangem.util.FormatUtil;
import com.tangem.wallet.R;
import java.io.IOException;
import java.util.Objects;
public class PreparePaymentActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback {
private static final int REQUEST_CODE_SCAN_QR = 1;
private static final int REQUEST_CODE_SEND_PAYMENT = 2;
private Button btnVerify;
private EditText etWallet;
private EditText etAmount;
private TextView tvCurrency;
private TextView tvCardId, tvBalance, tvBalanceEquivalent, tvAmountEquivalent;
private ImageView ivCamera;
private TextView tvAmountEquivalent;
boolean use_mCurrency;
private TangemCard mCard;
private NfcManager mNfcManager;
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -53,14 +52,14 @@ public class PreparePaymentActivity extends AppCompatActivity implements NfcAdap
mCard = new TangemCard(getIntent().getStringExtra("UID"));
mCard.LoadFromBundle(getIntent().getExtras().getBundle("Card"));
btnVerify = findViewById(R.id.btnVerify);
Button btnVerify = findViewById(R.id.btnVerify);
etWallet = findViewById(R.id.etWallet);
etAmount = findViewById(R.id.etAmount);
ivCamera = findViewById(R.id.ivCamera);
tvCurrency = findViewById(R.id.tvCurrency);
tvCardId = findViewById(R.id.tvCardID);
tvBalance = findViewById(R.id.tvBalance);
tvBalanceEquivalent = findViewById(R.id.tvBalanceEquivalent);
ImageView ivCamera = findViewById(R.id.ivCamera);
TextView tvCurrency = findViewById(R.id.tvCurrency);
TextView tvCardId = findViewById(R.id.tvCardID);
TextView tvBalance = findViewById(R.id.tvBalance);
TextView tvBalanceEquivalent = findViewById(R.id.tvBalanceEquivalent);
tvAmountEquivalent = findViewById(R.id.tvAmountEquivalent);
tvCardId.setText(mCard.getCIDDescription());
@ -135,29 +134,27 @@ public class PreparePaymentActivity extends AppCompatActivity implements NfcAdap
etAmount.setText(engine.GetBalanceValue(mCard));
}
btnVerify.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btnVerify.setOnClickListener(v -> {
String strAmount;
strAmount = etAmount.getText().toString();
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
CoinEngine engine1 = CoinEngineFactory.Create(mCard.getBlockchain());
try {
if (!engine.CheckAmount(mCard, etAmount.getText().toString())) {
etAmount.setError("Not enough funds on your card");
if (!Objects.requireNonNull(engine1).CheckAmount(mCard, etAmount.getText().toString())) {
etAmount.setError(getString(R.string.not_enough_funds_on_your_card));
}
} catch (Exception e) {
etAmount.setError("Unknown amount format");
etAmount.setError(getString(R.string.unknown_amount_format));
return;
}
boolean checkAddress = engine.ValdateAddress(etWallet.getText().toString(), mCard);
boolean checkAddress = engine1.ValdateAddress(etWallet.getText().toString(), mCard);
if (!checkAddress) {
etWallet.setError("Incorrect destination wallet address");
etWallet.setError(getString(R.string.incorrect_destination_wallet_address));
return;
}
if (etWallet.getText().toString().equals(mCard.getWallet())) {
etWallet.setError("Destination wallet address equal source address");
etWallet.setError(getString(R.string.destination_wallet_address_equal_source_address));
return;
}
@ -167,17 +164,30 @@ public class PreparePaymentActivity extends AppCompatActivity implements NfcAdap
intent.putExtra("Wallet", etWallet.getText().toString());
intent.putExtra("Amount", strAmount);
startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT);
}
});
ivCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ivCamera.setOnClickListener(v -> {
Intent intent = new Intent(getBaseContext(), QRScanActivity.class);
startActivityForResult(intent, REQUEST_CODE_SCAN_QR);
}
});
}
@Override
public void onResume() {
super.onResume();
mNfcManager.onResume();
}
@Override
public void onPause() {
super.onPause();
mNfcManager.onPause();
}
@Override
public void onStop() {
super.onStop();
mNfcManager.onStop();
}
@Override
@ -207,21 +217,4 @@ public class PreparePaymentActivity extends AppCompatActivity implements NfcAdap
}
}
@Override
public void onResume() {
super.onResume();
mNfcManager.onResume();
}
@Override
public void onPause() {
super.onPause();
mNfcManager.onPause();
}
@Override
public void onStop() {
super.onStop();
mNfcManager.onStop();
}
}

View file

@ -1,33 +0,0 @@
package com.tangem.presentation.activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.tangem.wallet.R;
public class SelectBlockchainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_blockchain);
// Spinner spBlockchain = (Spinner) findViewById(R.id.spBlockchain);
// ArrayAdapter<Blockchain> adapter = new ArrayAdapter<Blockchain>(this, android.R.layout.simple_spinner_item, Blockchain.values());
// spBlockchain.setAdapter(adapter);
// spBlockchain.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
// @Override
// public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Intent intent = new Intent();
// intent.putExtra("blockchain", Blockchain.values()[position].toString());
// setResult(RESULT_OK, intent);
// finish();
// }
//
// @Override
// public void onNothingSelected(AdapterView<?> parent) {
//
// }
// });
}
}

View file

@ -1,232 +0,0 @@
package com.tangem.presentation.activity
import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.preference.*
import android.text.TextUtils
import android.view.MenuItem
import com.tangem.wallet.R
/**
* A [PreferenceActivity] that presents a set of application settings. On
* handset devices, settings are presented as a single list. On tablets,
* settings are split by category, with category headers shown to the left of
* the list of settings.
*
* See [Android Design: Settings](http://developer.android.com/design/patterns/settings.html)
* for design guidelines and the [Settings API Guide](http://developer.android.com/guide/topics/ui/settings.html)
* for more information on developing a Settings UI.
*/
class SettingsFeatureActivity : AppCompatPreferenceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupActionBar()
}
/**
* Set up the [android.app.ActionBar], if the API is available.
*/
private fun setupActionBar() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
/**
* {@inheritDoc}
*/
override fun onIsMultiPane(): Boolean {
return isXLargeTablet(this)
}
/**
* {@inheritDoc}
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
override fun onBuildHeaders(target: List<PreferenceActivity.Header>) {
loadHeadersFromResource(R.xml.pref_headers, target)
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
override fun isValidFragment(fragmentName: String): Boolean {
return PreferenceFragment::class.java.name == fragmentName
|| GeneralPreferenceFragment::class.java.name == fragmentName
|| DataSyncPreferenceFragment::class.java.name == fragmentName
|| NotificationPreferenceFragment::class.java.name == fragmentName
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class GeneralPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_general)
setHasOptionsMenu(true)
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"))
bindPreferenceSummaryToValue(findPreference("example_list"))
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == android.R.id.home) {
startActivity(Intent(activity, SettingsFeatureActivity::class.java))
return true
}
return super.onOptionsItemSelected(item)
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class NotificationPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_notification)
setHasOptionsMenu(true)
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"))
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == android.R.id.home) {
startActivity(Intent(activity, SettingsFeatureActivity::class.java))
return true
}
return super.onOptionsItemSelected(item)
}
}
/**
* This fragment shows data and sync preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class DataSyncPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_data_sync)
setHasOptionsMenu(true)
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("sync_frequency"))
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == android.R.id.home) {
startActivity(Intent(activity, SettingsFeatureActivity::class.java))
return true
}
return super.onOptionsItemSelected(item)
}
}
companion object {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private val sBindPreferenceSummaryToValueListener = Preference.OnPreferenceChangeListener { preference, value ->
val stringValue = value.toString()
if (preference is ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
val listPreference = preference
val index = listPreference.findIndexOfValue(stringValue)
// Set the summary to reflect the new value.
preference.setSummary(
if (index >= 0)
listPreference.entries[index]
else
null)
} else if (preference is RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent)
} else {
val ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue))
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null)
} else {
// Set the summary to reflect the new ringtone display
// name.
val name = ringtone.getTitle(preference.getContext())
preference.setSummary(name)
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.summary = stringValue
}
true
}
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private fun isXLargeTablet(context: Context): Boolean {
return context.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK >= Configuration.SCREENLAYOUT_SIZE_XLARGE
}
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
* @see .sBindPreferenceSummaryToValueListener
*/
private fun bindPreferenceSummaryToValue(preference: Preference) {
// Set the listener to watch for value changes.
preference.onPreferenceChangeListener = sBindPreferenceSummaryToValueListener
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.context)
.getString(preference.key, ""))
}
}
}

View file

@ -1,87 +0,0 @@
package com.tangem.presentation.adapter;
import android.content.Context;
import android.os.Build;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.tangem.domain.wallet.TangemCard;
import com.tangem.wallet.R;
import static android.text.Html.FROM_HTML_MODE_COMPACT;
/**
* Created by dvol on 17.07.2017.
*/
public class CardUnspentListAdapter extends BaseAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
private TangemCard mCard;
public CardUnspentListAdapter(LayoutInflater layoutInflater, TangemCard card) {
mLayoutInflater = layoutInflater;
mContext = layoutInflater.getContext();
mCard = card;
}
@Override
public int getCount() {
if (mCard != null && mCard.getUnspentTransactions() != null)
return mCard.getUnspentTransactions().size();
return 0;
}
@Override
public Object getItem(int i) {
if (mCard != null && mCard.getUnspentTransactions() != null)
return mCard.getUnspentTransactions().get(i);
return null;
}
@Override
public long getItemId(int i) {
if (mCard != null && mCard.getUnspentTransactions() != null)
return mCard.getUnspentTransactions().get(i).txID.hashCode();
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.item_list_card_unspent, viewGroup,
false);
}
TextView tvItem = (TextView) convertView.findViewById(R.id.tvItem);
TangemCard.UnspentTransaction unspentTransaction = (TangemCard.UnspentTransaction) getItem(position);
String html = String.format("<b>%d mBTC</b><br>%s", unspentTransaction.Amount, unspentTransaction.txID);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tvItem.setText(Html.fromHtml(html, FROM_HTML_MODE_COMPACT));
} else {
tvItem.setText(Html.fromHtml(html.toString()));
}
return convertView;
}
public void Clear() {
mCard.getUnspentTransactions().clear();
notifyDataSetChanged();
}
public void UpdateUnspent(String tx_hash, int value, int height) {
TangemCard.UnspentTransaction newUT = new TangemCard.UnspentTransaction();
newUT.txID = tx_hash;
newUT.Amount = value;
newUT.Height = height;
mCard.getUnspentTransactions().add(newUT);
notifyDataSetChanged();
}
}

View file

@ -1,152 +0,0 @@
package com.tangem.presentation.fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.tangem.wallet.R;
import com.tangem.domain.wallet.TangemCard;
import java.util.Hashtable;
import static android.content.Context.CLIPBOARD_SERVICE;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link WalletInfo#newInstance} factory method to
* create an instance of this fragment.
*/
public class WalletInfo extends Fragment {
// TODO: Rename and change types of parameters
private TangemCard mCard;
private OnFragmentInteractionListener mListener;
public WalletInfo() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @return A new instance of fragment WalletInfo.
*/
// TODO: Rename and change types and number of parameters
public static WalletInfo newInstance(TangemCard card) {
WalletInfo fragment = new WalletInfo();
Bundle args = new Bundle();
args.putString("UID",card.getUID());
card.SaveToBundle(args);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mCard = new TangemCard(getArguments().getString("UID"));
mCard.LoadFromBundle(getArguments());
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View result=inflater.inflate(R.layout.fr_wallet_info, container, false);
ImageView mImage= (ImageView)result.findViewById(R.id.qrWallet);
try {
mImage.setImageBitmap(generateQrCode(mCard.getWallet()));
} catch (WriterException e) {
e.printStackTrace();
}
TextView mText=(TextView)result.findViewById(R.id.strWallet);
mText.setText(mCard.getWallet());
mText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
TextView mText = (TextView) view;
ClipboardManager clipboard = (ClipboardManager)getActivity().getSystemService(CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(ClipData.newPlainText(mText.getText(), mText.getText()));
Toast.makeText(getContext(),"Copied to clipboard",Toast.LENGTH_LONG).show();
}
});
return result;
}
public static Bitmap generateQrCode(String myCodeText) throws WriterException {
Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<EncodeHintType, ErrorCorrectionLevel>();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // H = 30% damage
QRCodeWriter qrCodeWriter = new QRCodeWriter();
int size = 256;
BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hintMap);
int width = bitMatrix.getWidth();
Bitmap bmp = Bitmap.createBitmap(width, width, Bitmap.Config.RGB_565);
for (int x = 0; x < width; x++) {
for (int y = 0; y < width; y++) {
bmp.setPixel(y, x, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE);
}
}
return bmp;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
// void onFragmentInteraction(Uri uri);
}
}

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z"/>
</vector>

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.5,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zm6.5,-6v-5.5c0,-3.07 -2.13,-5.64 -5,-6.32V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5v0.68c-2.87,0.68 -5,3.25 -5,6.32V16l-2,2v1h17v-1l-2,-2z"/>
</vector>

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-.25 1.97,-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01.25,-1.97.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z"/>
</vector>

View file

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.tangem.presentation.activity.CardInfoActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.tangem.presentation.activity.QRScanActivity">
</android.support.constraint.ConstraintLayout>

View file

@ -1,12 +0,0 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rvBlockchain"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>

View file

@ -1,24 +0,0 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.tangem.wallet.WalletUnspentFragment">
<!-- TODO: Update blank fragment layout -->
<ListView
android:id="@+id/lvHistory"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabRefresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_search_gray" />
</FrameLayout>

View file

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.tangem.wallet.com.tangem.presentation.fragment.WalletInfoFragment">
<ImageView
android:id="@+id/qrWallet"
android:layout_width="256dp"
android:layout_height="256dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="83dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@color/cardview_light_background"
tools:layout_editor_absoluteX="72dp" />
<TextView
android:id="@+id/strWallet"
android:layout_width="347dp"
android:layout_height="39dp"
android:layout_marginBottom="76dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="none|textPersonName"
android:singleLine="false"
android:text="N/A"
android:textAlignment="center"
android:textSize="12dp"
android:textStyle="bold"
android:typeface="monospace"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.509"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/qrWallet"
tools:layout_editor_absoluteX="2dp" />
</android.support.constraint.ConstraintLayout>

View file

@ -1,24 +0,0 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.tangem.wallet.WalletUnspentFragment">
<!-- TODO: Update blank fragment layout -->
<ListView
android:id="@+id/lvUnspent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabRefresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_search_gray" />
</FrameLayout>

View file

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imgBlockchain"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/ic_logo_small"
android:layout_marginLeft="10dp"
android:layout_gravity="center"/>
<TextView
android:id="@+id/tvCurrency"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_large"
android:fontFamily="@font/raleway_r"
android:layout_margin="8dp"/>
</LinearLayout>

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="96dp">
<TextView
android:id="@+id/tvItem"
style="@style/Base.TextAppearance.AppCompat.Small"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:text="History"/>
<View
android:id="@+id/separator"
style="@style/thin_separator"/>
</RelativeLayout>

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="96dp">
<TextView
android:id="@+id/tvItem"
style="@style/Base.TextAppearance.AppCompat.Small"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:text="Unspent"/>
<View
android:id="@+id/separator"
style="@style/thin_separator"/>
</RelativeLayout>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<Button
android:id="@+id/btnMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/imgMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>

View file

@ -1,10 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.bitex.Wallet.CardInfoActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>

View file

@ -13,12 +13,9 @@
<string name="enable_nfc">This app is useless when NFC is disabled. Reader mode depends on it. Hit OK to go to Settings, where you can enable NFC.</string>
<string name="cmd_suffix">command</string>
<string name="rsp_suffix">response</string>
<string name="action_settings">Settings</string>
<string name="title_activity_card_info">CardInfoActivity</string>
<string name="section_format">Hello World from section: %1$d</string>
<string name="fingerprint_authenticate_success">Successfully authenticated!</string>
<string name="pin_save_success">Successfully saved!</string>
<string name="pin_save_fail">Saving pin failed</string>
<string name="error_empty_pin">PIN is empty</string>
<string name="error_pin_confirmation_failed">Please enter the PIN for confirmation!</string>
@ -64,14 +61,11 @@
<!-- MainActivity, Main -->
<string name="tap_tangem_card">Tap Tangem card with your smartphone</string>
<string name="scan_banknote">Scan a banknote with your \n smartphone as shown above</string>
<string name="wallet">Wallet</string>
<string name="last_unspent">Last unspent</string>
<string name="no_wallet">NO WALLET</string>
<string name="erased_wallet">ERASED WALLET</string>
<string name="invalid_card">INVALID CARD</string>
<string name="developer_kit_spaces">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DEVELOPER&#160;&#160;&#160;&#160;&#160;KIT&#160;&#160;&#160;&#160;&#160;</string>
<string name="banknote_banknote">&#160;&#160;BANKNOTE&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;BANKNOTE</string>
<string name="reusable_reusable">&#160;&#160;&#160;REUSABLE&#160;&#160;&#160;&#160;&#160;&#160;&#160;REUSABLE&#160;&#160;&#160;</string>
@ -144,77 +138,10 @@
<!-- PurgeActivity -->
<string name="cannot_erase_wallet">Cannot erase wallet. Make sure you enter correct PIN2!</string>
<!-- Strings related to Settings -->
<!-- Example General settings -->
<string name="pref_header_general">General</string>
<string name="pref_title_social_recommendations">Enable social recommendations</string>
<string name="pref_description_social_recommendations">Recommendations for people to contact based on your message history</string>
<string name="pref_title_display_name">Display name</string>
<string name="pref_default_display_name">John Smith</string>
<string name="pref_title_add_friends_to_messages">Add friends to messages</string>
<string-array name="pref_example_list_titles">
<item>Always</item>
<item>When possible</item>
<item>Never</item>
</string-array>
<string-array name="pref_example_list_values">
<item>1</item>
<item>0</item>
<item>-1</item>
</string-array>
<!-- Example settings for Data & Sync -->
<string name="pref_header_data_sync">Data &amp; sync</string>
<string name="pref_title_sync_frequency">Sync frequency</string>
<string-array name="pref_sync_frequency_titles">
<item>15 minutes</item>
<item>30 minutes</item>
<item>1 hour</item>
<item>3 hours</item>
<item>6 hours</item>
<item>Never</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>-1</item>
</string-array>
<string-array name="list_preference_entries">
<item>Entry 1</item>
<item>Entry 2</item>
<item>Entry 3</item>
</string-array>
<string-array name="list_preference_entry_values">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="multi_select_list_preference_default_value"/>
<string name="pref_title_system_sync_settings">System sync settings</string>
<!-- Example settings for Notifications -->
<string name="pref_header_notifications">Notifications</string>
<string name="pref_title_new_message_notifications">New message notifications</string>
<string name="pref_title_ringtone">Ringtone</string>
<string name="pref_ringtone_silent">Silent</string>
<string name="pref_title_vibrate">Vibrate</string>
<!-- PreparePaymentActivity -->
<string name="not_enough_funds_on_your_card">Not enough funds on your card</string>
<string name="unknown_amount_format">Unknown amount format</string>
<string name="incorrect_destination_wallet_address">Incorrect destination wallet address</string>
<string name="destination_wallet_address_equal_source_address">Destination wallet address equal source address</string>
</resources>

View file

@ -15,7 +15,6 @@
<style name="spinner_dropdown_item_actionbar" parent="Widget.AppCompat.DropDownItem.Spinner">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">40dp</item>
-->
<item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:singleLine">true</item>
<item name="android:textSize">@dimen/text_size_medium</item>

View file

@ -1,21 +0,0 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
dismiss it. -->
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
<ListPreference
android:defaultValue="180"
android:entries="@array/pref_sync_frequency_titles"
android:entryValues="@array/pref_sync_frequency_values"
android:key="sync_frequency"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/pref_title_sync_frequency"/>
<!-- This preference simply launches an intent when selected. Use this UI sparingly, per
design guidelines. -->
<Preference android:title="@string/pref_title_system_sync_settings">
<intent android:action="android.settings.SYNC_SETTINGS"/>
</Preference>
</PreferenceScreen>

View file

@ -1,33 +0,0 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="true"
android:key="example_switch"
android:summary="@string/pref_description_social_recommendations"
android:title="@string/pref_title_social_recommendations"/>
<!-- NOTE: EditTextPreference accepts EditText attributes. -->
<!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
<EditTextPreference
android:capitalize="words"
android:defaultValue="@string/pref_default_display_name"
android:inputType="textCapWords"
android:key="example_text"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/pref_title_display_name"/>
<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
dismiss it. -->
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
<ListPreference
android:defaultValue="-1"
android:entries="@array/pref_example_list_titles"
android:entryValues="@array/pref_example_list_values"
android:key="example_list"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/pref_title_add_friends_to_messages"/>
</PreferenceScreen>

View file

@ -1,20 +0,0 @@
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<!-- These settings headers are only used on tablets. -->
<header
android:fragment="com.tangem.presentation.activity.SettingsFeatureActivity$GeneralPreferenceFragment"
android:icon="@drawable/ic_info_black_24dp"
android:title="@string/pref_header_general"/>
<header
android:fragment="com.tangem.presentation.activity.SettingsFeatureActivity$NotificationPreferenceFragment"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/pref_header_notifications"/>
<header
android:fragment="com.tangem.presentation.activity.SettingsFeatureActivity$DataSyncPreferenceFragment"
android:icon="@drawable/ic_sync_black_24dp"
android:title="@string/pref_header_data_sync"/>
</preference-headers>

View file

@ -1,27 +0,0 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- A 'parent' preference, which enables/disables child preferences (below)
when checked/unchecked. -->
<SwitchPreference
android:defaultValue="true"
android:key="notifications_new_message"
android:title="@string/pref_title_new_message_notifications"/>
<!-- Allows the user to choose a ringtone in the 'notification' category. -->
<!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
<!-- NOTE: RingtonePreference's summary should be set to its value by the activity code. -->
<RingtonePreference
android:defaultValue="content://settings/system/notification_sound"
android:dependency="notifications_new_message"
android:key="notifications_new_message_ringtone"
android:ringtoneType="notification"
android:title="@string/pref_title_ringtone"/>
<!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
<SwitchPreference
android:defaultValue="true"
android:dependency="notifications_new_message"
android:key="notifications_new_message_vibrate"
android:title="@string/pref_title_vibrate"/>
</PreferenceScreen>