Updated on 2026-08-14

This commit is contained in:
Tangem 2018-06-19 13:21:54 +03:00
parent 2ed8c3fcc2
commit 6e1191cf10
10 changed files with 720 additions and 739 deletions

Binary file not shown.

View file

@ -22,14 +22,14 @@ android {
buildTypes {
release {
// debuggable false
// minifyEnabled false
debuggable false
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
debug {
// debuggable true
// minifyEnabled false
debuggable true
minifyEnabled false
applicationIdSuffix ".debug"
signingConfig signingConfigs.debug
}

View file

@ -28,44 +28,41 @@ import javax.net.ssl.HttpsURLConnection;
public class InfuraTask extends AsyncTask<InfuraRequest, Void, List<InfuraRequest>> {
private Exception exception;
private Blockchain blockchain;
public InfuraTask(Blockchain blockchainNet)
{
public InfuraTask(Blockchain blockchainNet) {
blockchain = blockchainNet;
}
boolean useOurNode = false;
protected List<InfuraRequest> doInBackground(InfuraRequest... requests) {
List<InfuraRequest> result = new ArrayList<>();
for (int i = 0; i < requests.length; i++) {
result.add(requests[i]);
}
for (InfuraRequest request: result)
{
for (InfuraRequest request : result) {
HttpURLConnection httpcon = null;
try {
URL url = new URL("https://rinkeby.infura.io/AfWg0tmYEX5Kukn2UkKV");
if(blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token){
if(useOurNode) {
if (blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token) {
if (useOurNode) {
URL tmp = new URL("http://52.230.23.88");
url = new URL(tmp.getProtocol(), tmp.getHost(), 27172, tmp.getFile());
}else
} else
url = new URL("https://mainnet.infura.io/AfWg0tmYEX5Kukn2UkKV");
}
if(useOurNode)
{
httpcon = (HttpURLConnection)url.openConnection();
}
else
{
httpcon = (HttpsURLConnection)url.openConnection();
if (useOurNode) {
httpcon = (HttpURLConnection) url.openConnection();
} else {
httpcon = (HttpsURLConnection) url.openConnection();
}
if(httpcon == null)
{
if (httpcon == null) {
request.error = String.format("Cann't connect to %s", url.getHost());
return result;
}
@ -75,15 +72,13 @@ public class InfuraTask extends AsyncTask<InfuraRequest, Void, List<InfuraReques
String params = request.getAsString();
OutputStream os = httpcon.getOutputStream();
if(os == null)
{
if (os == null) {
request.error = String.format("Cann't recieve data from %s", url.getHost());
return result;
}
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
if(writer == null)
{
if (writer == null) {
request.error = String.format("Cann't send data to %s", url.getHost());
}
@ -95,7 +90,7 @@ public class InfuraTask extends AsyncTask<InfuraRequest, Void, List<InfuraReques
httpcon.connect();
request.getParams();
System.out.println("code:"+httpcon.getResponseCode());
System.out.println("code:" + httpcon.getResponseCode());
int code = httpcon.getResponseCode();
BufferedReader in = new BufferedReader(
@ -122,9 +117,8 @@ public class InfuraTask extends AsyncTask<InfuraRequest, Void, List<InfuraReques
}
public String getValidationNodeDescription() {
if(blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token)
{
if(useOurNode)
if (blockchain == Blockchain.Ethereum || blockchain == Blockchain.Token) {
if (useOurNode)
return "52.230.23.88:27172";
else
return "Infura, infura.io";

View file

@ -19,6 +19,10 @@ import java.util.List;
*/
public class TangemCard {
public static final String EXTRA_CARD = "Card";
public static final String EXTRA_UID = "UID";
private byte[] CID;
private Status status;
private String wallet;
@ -174,7 +178,6 @@ public class TangemCard {
return walletPublicKeyValid;
}
public void setCardPublicKey(byte[] publicKey) {
pbCardKey = publicKey;
}
@ -210,7 +213,6 @@ public class TangemCard {
}
}
public String getAmountDescription(Double amount) {
if (amount < 10) {
amount *= 1000.0; //todo: really?
@ -615,7 +617,6 @@ public class TangemCard {
return tokensDecimal;
}
public Issuer getIssuer() {
return issuer;
}
@ -653,7 +654,6 @@ public class TangemCard {
return "";
}
private int pauseBeforePIN2 = 0;
public void setPauseBeforePIN2(int value) {
@ -696,7 +696,8 @@ public class TangemCard {
public Boolean useSmartSecurityDelay() {
if (settingsMask == null) return null;
return (settingsMask.intValue() & SettingsMask.SmartSecurityDelay) != 0; }
return (settingsMask.intValue() & SettingsMask.SmartSecurityDelay) != 0;
}
public enum PIN2_Mode {Unchecked, DefaultPIN2, CustomPIN2}
@ -1004,7 +1005,7 @@ public class TangemCard {
}
public int GetTimestamp(int height) {
if(mHeaders == null)
if (mHeaders == null)
return 0;
for (int i = 0; i < mHeaders.size(); ++i) {
if (mHeaders.get(i).Height == height) {
@ -1135,6 +1136,7 @@ public class TangemCard {
public void clearDenomination() {
Denomination = null;
}
public void setError(String error) {
this.error = error;
}
@ -1377,5 +1379,4 @@ public class TangemCard {
}
public EncryptionMode encryptionMode = EncryptionMode.None;
}
}

View file

@ -40,13 +40,10 @@ public class WaitSecurityDelayDialog extends DialogFragment {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
progressBar.post(new Runnable() {
@Override
public void run() {
int progress = WaitSecurityDelayDialog.this.progressBar.getProgress();
if (progress < WaitSecurityDelayDialog.this.progressBar.getMax()) {
WaitSecurityDelayDialog.this.progressBar.setProgress(progress + 1000);
}
progressBar.post(() -> {
int progress = WaitSecurityDelayDialog.this.progressBar.getProgress();
if (progress < WaitSecurityDelayDialog.this.progressBar.getMax()) {
WaitSecurityDelayDialog.this.progressBar.setProgress(progress + 1000);
}
});
}
@ -70,22 +67,19 @@ public class WaitSecurityDelayDialog extends DialogFragment {
}
public void setRemainingTimeout(final int msec) {
progressBar.post(new Runnable() {
@Override
public void run() {
int progress = WaitSecurityDelayDialog.this.progressBar.getProgress();
if (timer != null) {
// we get delay latency from card for first time - don't change progress by timer, only by card answer
progressBar.setMax(progress + msec);
timer.cancel();
timer = null;
progressBar.post(() -> {
int progress = WaitSecurityDelayDialog.this.progressBar.getProgress();
if (timer != null) {
// we get delay latency from card for first time - don't change progress by timer, only by card answer
progressBar.setMax(progress + msec);
timer.cancel();
timer = null;
} else {
int newProgress = progressBar.getMax() - msec;
if (newProgress > progress) {
progressBar.setProgress(newProgress);
} else {
int newProgress = progressBar.getMax() - msec;
if (newProgress > progress) {
progressBar.setProgress(newProgress);
} else {
progressBar.setMax(progress + msec);
}
progressBar.setMax(progress + msec);
}
}
});
@ -101,68 +95,61 @@ public class WaitSecurityDelayDialog extends DialogFragment {
return instance;
}
private final static int MinRemainingDelayToShowDialog=1000;
private final static int DelayBeforeShowDialog=5000;
private final static int MinRemainingDelayToShowDialog = 1000;
private final static int DelayBeforeShowDialog = 5000;
public static void onReadBeforeRequest(final Activity activity, final int timeout) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (timerToShowDelayDialog != null || timeout < DelayBeforeShowDialog+MinRemainingDelayToShowDialog) return;
timerToShowDelayDialog = new Timer();
timerToShowDelayDialog.schedule(new TimerTask() {
@Override
public void run() {
if (WaitSecurityDelayDialog.instance != null) return;
instance = new WaitSecurityDelayDialog();
instance.setup(timeout, DelayBeforeShowDialog);
instance.setCancelable(false);
instance.show(activity.getFragmentManager(), "WaitSecurityDelayDialog");
}
}, DelayBeforeShowDialog);
}
activity.runOnUiThread(() -> {
if (timerToShowDelayDialog != null || timeout < DelayBeforeShowDialog + MinRemainingDelayToShowDialog)
return;
timerToShowDelayDialog = new Timer();
timerToShowDelayDialog.schedule(new TimerTask() {
@Override
public void run() {
if (WaitSecurityDelayDialog.instance != null) return;
instance = new WaitSecurityDelayDialog();
instance.setup(timeout, DelayBeforeShowDialog);
instance.setCancelable(false);
instance.show(activity.getFragmentManager(), "WaitSecurityDelayDialog");
}
}, DelayBeforeShowDialog);
});
}
public static void onReadAfterRequest(final Activity activity) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (timerToShowDelayDialog == null) return;
timerToShowDelayDialog.cancel();
timerToShowDelayDialog = null;
}
activity.runOnUiThread(() -> {
if (timerToShowDelayDialog == null) return;
timerToShowDelayDialog.cancel();
timerToShowDelayDialog = null;
});
}
public static void OnReadWait(final Activity activity, final int msec) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (timerToShowDelayDialog != null) {
timerToShowDelayDialog.cancel();
timerToShowDelayDialog = null;
}
activity.runOnUiThread(() -> {
if (timerToShowDelayDialog != null) {
timerToShowDelayDialog.cancel();
timerToShowDelayDialog = null;
}
if (msec == 0) {
if (instance != null) {
instance.dismiss();
instance = null;
}
return;
if (msec == 0) {
if (instance != null) {
instance.dismiss();
instance = null;
}
if (instance == null) {
if( msec>MinRemainingDelayToShowDialog ) {
instance = new WaitSecurityDelayDialog();
// 1000ms - card delay notification interval
instance.setup(msec + 1000, 1000);
instance.setCancelable(false);
instance.show(activity.getFragmentManager(), "WaitSecurityDelayDialog");
}
} else {
instance.setRemainingTimeout(msec);
return;
}
if (instance == null) {
if (msec > MinRemainingDelayToShowDialog) {
instance = new WaitSecurityDelayDialog();
// 1000ms - card delay notification interval
instance.setup(msec + 1000, 1000);
instance.setCancelable(false);
instance.show(activity.getFragmentManager(), "WaitSecurityDelayDialog");
}
} else {
instance.setRemainingTimeout(msec);
}
});
}
}
}

View file

@ -18,6 +18,7 @@ import android.nfc.tech.IsoDep;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
@ -59,6 +60,7 @@ import com.tangem.domain.wallet.PINStorage;
import com.tangem.domain.wallet.SharedData;
import com.tangem.domain.wallet.TangemCard;
import com.tangem.presentation.activity.CreateNewWalletActivity;
import com.tangem.presentation.activity.MainActivity;
import com.tangem.presentation.activity.PreparePaymentActivity;
import com.tangem.presentation.activity.PurgeActivity;
import com.tangem.presentation.activity.RequestPINActivity;
@ -98,12 +100,27 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
private static final int REQUEST_CODE_SWAP_PIN = 8;
private TangemCard mCard;
private TextView tvCardID, tvBalance, tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, lbInputs, tvPurge, tvError, tvMessage, tvIssuer, tvIssuerData, tvBlockchain, tvLastInput, tvLastOutput, lbLastOutput, tvValidationNode;
private TextView tvCardID;
private TextView tvBalance;
private TextView tvOffline;
private TextView tvBalanceEquivalent;
private TextView tvWallet;
private TextView tvInputs;
private TextView tvError;
private TextView tvMessage;
private TextView tvIssuer;
private TextView tvIssuerData;
private TextView tvBlockchain;
private TextView tvLastInput;
private TextView tvLastOutput;
private TextView lbLastOutput;
private TextView tvValidationNode;
private TextView tvHeader, tvCaution;
private ImageView imgLookup;
private TextView tvLookup;
private ProgressBar progressBar;
private ImageView ivBlockchain, ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion, ivQR;
private ImageView ivBlockchain;
private ImageView ivPIN;
private ImageView ivPIN2orSecurityDelay;
private ImageView ivDeveloperVersion;
private SwipeRefreshLayout mSwipeRefreshLayout;
private List<UpdateWalletInfoTask> updateTasks = new ArrayList<>();
private NfcManager mNfcManager;
@ -115,6 +132,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
private Timer timerHideErrorAndMessage = null;
private String newPIN = "", newPIN2 = "";
private AppCompatButton btnLoad, btnExtract;
private FloatingActionButton fabPurge, fabNFC;
public LoadedWallet() {
@ -580,7 +598,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
public View onCreateView(@NonNull final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fr_loaded_wallet, container, false);
mNfcManager = new NfcManager(this.getActivity(), this);
mNfcManager = new NfcManager(getActivity(), this);
mSwipeRefreshLayout = v.findViewById(R.id.swipe_container);
tvBalance = v.findViewById(R.id.tvBalance);
@ -588,16 +606,15 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
tvCardID = v.findViewById(R.id.tvCardID);
tvWallet = v.findViewById(R.id.tvWallet);
tvInputs = v.findViewById(R.id.tvInputs);
lbInputs = v.findViewById(R.id.lbInputs);
TextView lbInputs = v.findViewById(R.id.lbInputs);
tvLastOutput = v.findViewById(R.id.tvLastOutput);
lbLastOutput = v.findViewById(R.id.lbLastOutput);
tvError = v.findViewById(R.id.tvError);
tvMessage = v.findViewById(R.id.tvMessage);
tvIssuer = v.findViewById(R.id.tvIssuer);
tvIssuerData = v.findViewById(R.id.tvIssuerData);
tvHeader = v.findViewById(R.id.tvHeader);
tvCaution = v.findViewById(R.id.tvCaution);
imgLookup = v.findViewById(R.id.imgLookup);
ImageView imgLookup = v.findViewById(R.id.imgLookup);
tvValidationNode = v.findViewById(R.id.tvValidationNode);
progressBar = v.findViewById(R.id.progressBar);
tvBlockchain = v.findViewById(R.id.tvBlockchain);
@ -605,43 +622,30 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
ivPIN = v.findViewById(R.id.imgPIN);
ivPIN2orSecurityDelay = v.findViewById(R.id.imgPIN2orSecurityDelay);
ivDeveloperVersion = v.findViewById(R.id.imgDeveloperVersion);
ivQR = v.findViewById(R.id.qrWallet);
tvLookup = v.findViewById(R.id.tvLookup);
tvPurge = v.findViewById(R.id.tvPurge);
ImageView ivQR = v.findViewById(R.id.qrWallet);
TextView tvLookup = v.findViewById(R.id.tvLookup);
fabPurge = v.findViewById(R.id.fabPurge);
fabNFC = v.findViewById(R.id.fabNFC);
btnLoad = v.findViewById(R.id.btnLoad);
btnExtract = v.findViewById(R.id.btnExtract);
tvBalanceEquivalent = v.findViewById(R.id.tvBalanceEquivalent);
mSwipeRefreshLayout.setOnRefreshListener(this);
mCard = new TangemCard(getActivity().getIntent().getStringExtra("UID"));
mCard.LoadFromBundle(getActivity().getIntent().getExtras().getBundle("Card"));
mCard = new TangemCard(Objects.requireNonNull(getActivity()).getIntent().getStringExtra(TangemCard.EXTRA_CARD));
mCard.LoadFromBundle(Objects.requireNonNull(getActivity().getIntent().getExtras()).getBundle(TangemCard.EXTRA_CARD));
if (mCard.getBlockchain() == Blockchain.Token) {
//tvBalance.setLines(2);
if (mCard.getBlockchain() == Blockchain.Token)
tvBalance.setSingleLine(false);
}
tvBalanceEquivalent = v.findViewById(R.id.tvBalanceEquivalent);
final CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
boolean visibleFlag = engine != null ? engine.InOutPutVisible() : true;
int visibleIOPuts = visibleFlag ? View.VISIBLE : View.GONE;
if (tvInputs != null) {
tvInputs.setVisibility(visibleIOPuts);
}
if (lbInputs != null) {
lbInputs.setVisibility(visibleIOPuts);
}
if (tvLastOutput != null) {
tvLastOutput.setVisibility(visibleIOPuts);
}
if (lbLastOutput != null) {
lbLastOutput.setVisibility(visibleIOPuts);
}
tvInputs.setVisibility(visibleIOPuts);
lbInputs.setVisibility(visibleIOPuts);
tvLastOutput.setVisibility(visibleIOPuts);
try {
ivQR.setImageBitmap(generateQrCode(Objects.requireNonNull(engine).getShareWalletURI(mCard).toString()));
@ -649,31 +653,44 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
e.printStackTrace();
}
if (imgLookup != null) {
imgLookup.setOnClickListener(v15 -> {
if (!mCard.hasBalanceInfo()) {
return;
}
CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain());
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Objects.requireNonNull(engineClick).getShareWalletURIExplorer(mCard));
startActivity(browserIntent);
});
updateViews();
if (!mCard.hasBalanceInfo()) {
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.postDelayed(this::onRefresh, 1000);
}
if (tvLookup != null) {
tvLookup.setOnClickListener(v14 -> {
if (!mCard.hasBalanceInfo()) {
return;
imgLookup.setOnClickListener(v15 -> {
if (!mCard.hasBalanceInfo()) return;
CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain());
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Objects.requireNonNull(engineClick).getShareWalletURIExplorer(mCard));
startActivity(browserIntent);
});
tvLookup.setOnClickListener(v14 -> {
if (!mCard.hasBalanceInfo()) return;
CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain());
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Objects.requireNonNull(engineClick).getShareWalletURIExplorer(mCard));
startActivity(browserIntent);
});
tvWallet.setOnClickListener(v12 -> doShareWallet(false));
ivQR.setOnClickListener(v1 -> doShareWallet(true));
btnLoad.setOnClickListener(v1 -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Objects.requireNonNull(CoinEngineFactory.Create(mCard.getBlockchain())).getShareWalletURI(mCard));
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
}
CoinEngine engineClick = CoinEngineFactory.Create(mCard.getBlockchain());
);
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Objects.requireNonNull(engineClick).getShareWalletURIExplorer(mCard));
startActivity(browserIntent);
});
}
fabPurge.setOnClickListener(v16 -> showMenu(fabPurge));
fabNFC.setOnClickListener(view -> {
Intent intent = new Intent(getContext(), MainActivity.class);
startActivity(intent);
});
btnExtract.setOnClickListener(v13 -> {
if (!mCard.hasBalanceInfo()) {
@ -701,23 +718,6 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
startActivityForResult(intent, REQUEST_CODE_SEND_PAYMENT);
});
updateViews();
if (!mCard.hasBalanceInfo()) {
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.postDelayed(this::onRefresh, 1000);
}
tvWallet.setOnClickListener(v12 -> doShareWallet(false));
ivQR.setOnClickListener(v1 -> doShareWallet(true));
btnLoad.setOnClickListener(v1 -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Objects.requireNonNull(CoinEngineFactory.Create(mCard.getBlockchain())).getShareWalletURI(mCard));
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
}
);
tvPurge.setOnClickListener(v16 -> showMenu(tvPurge));
return v;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
<!-- drawable/ic_nfc_white_24dpnfc_white_24dp.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#fff" android:pathData="M10.59,7.66C10.59,7.66 11.19,7.39 11.57,7.82C11.95,8.26 12.92,9.94 12.92,11.62C12.92,13.3 12.5,15.09 12.05,15.68C11.62,16.28 11.19,16.28 10.86,16.06C10.54,15.85 5.5,12 5.23,11.89C4.95,11.78 4.85,12.05 5.12,13.5C5.39,15 4.95,15.41 4.57,15.47C4.2,15.5 3.06,15.2 3,12.16C2.95,9.13 3.76,8.64 4.14,8.64C4.85,8.64 10.27,13.5 10.64,13.46C10.97,13.41 11.13,11.35 10.5,9.72C9.78,7.96 10.59,7.66 10.59,7.66M19.3,4.63C21.12,8.24 21,11.66 21,12C21,12.34 21.12,15.76 19.3,19.37C19.3,19.37 18.83,19.92 18.12,19.59C17.42,19.26 17.66,18.4 17.66,18.4C17.66,18.4 19.14,15.55 19.1,12.05V12C19.14,8.5 17.66,5.6 17.66,5.6C17.66,5.6 17.42,4.74 18.12,4.41C18.83,4.08 19.3,4.63 19.3,4.63M15.77,6.25C17.26,8.96 17.16,11.66 17.14,12C17.16,12.34 17.26,14.92 15.77,17.85C15.77,17.85 15.3,18.4 14.59,18.07C13.89,17.74 14.13,16.88 14.13,16.88C14.13,16.88 15.09,15.5 15.24,12.05V12C15.14,8.53 14.13,7.23 14.13,7.23C14.13,7.23 13.89,6.36 14.59,6.04C15.3,5.71 15.77,6.25 15.77,6.25Z" />
</vector>

View file

@ -0,0 +1,8 @@
<!-- drawable/ic_wrench_white_24dp.xmlwhite_24dp.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#fff" android:pathData="M22.7,19L13.6,9.9C14.5,7.6 14,4.9 12.1,3C10.1,1 7.1,0.6 4.7,1.7L9,6L6,9L1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1C4.8,14 7.5,14.5 9.8,13.6L18.9,22.7C19.3,23.1 19.9,23.1 20.3,22.7L22.6,20.4C23.1,20 23.1,19.3 22.7,19Z" />
</vector>

View file

@ -215,8 +215,7 @@
android:gravity="top|center"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:paddingRight="8dp"
>
android:paddingRight="8dp">
<ImageView
android:id="@+id/qrWallet"
@ -441,7 +440,8 @@
<LinearLayout
android:id="@+id/rlToolButtons"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/rlCardIdAndIcons"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
@ -450,29 +450,29 @@
<android.support.v7.widget.AppCompatButton
android:id="@+id/btnLoad"
style="@style/AppTheme.RoundedCornerMaterialButton"
android:layout_width="120dp"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:text="@string/load"/>
<TextView
android:id="@+id/tvPurge"
android:layout_width="40dp"
android:layout_height="36dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="@drawable/ic_show_menu"
android:backgroundTint="@color/colorPrimaryDark"
android:fontFamily="@font/raleway_r"
android:gravity="center_vertical"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="@dimen/text_size_medium"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabPurge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
app:fabSize="mini"
app:srcCompat="@drawable/ic_wrench_white_24dp"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabNFC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
app:fabSize="mini"
app:srcCompat="@drawable/ic_nfc_white_24dp"/>
<android.support.v7.widget.AppCompatButton
android:id="@+id/btnExtract"
style="@style/AppTheme.RoundedCornerMaterialButton"
android:layout_width="120dp"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:text="@string/extract"/>
</LinearLayout>