mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-04 17:28:42 +02:00
Compare commits
89 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
46add5e927 | ||
![]() |
fa0692ceab | ||
![]() |
ff4f4a1c2c | ||
![]() |
79abb89725 | ||
![]() |
ef8301fd6f | ||
![]() |
3a15c842ff | ||
![]() |
1697da55b5 | ||
![]() |
454f3e412a | ||
![]() |
d803a1e220 | ||
![]() |
f2fe781cb5 | ||
![]() |
dcf60ae193 | ||
![]() |
ffdf54c2e1 | ||
![]() |
c060a2ab88 | ||
![]() |
05fc654f3a | ||
![]() |
c32d157150 | ||
![]() |
74e9278baa | ||
![]() |
e41e344d63 | ||
![]() |
e66875437d | ||
![]() |
c1d2db3d7d | ||
![]() |
0c9a2f5e01 | ||
![]() |
64616e3921 | ||
![]() |
82b4d66987 | ||
![]() |
10f2bc6561 | ||
![]() |
2ed9a78d9e | ||
![]() |
ca19f32f8f | ||
![]() |
4431d74051 | ||
![]() |
f00da6ecda | ||
![]() |
1cecd0b718 | ||
![]() |
a0d6117bbb | ||
![]() |
0b0648a172 | ||
![]() |
775dcf01ae | ||
![]() |
aed4051d44 | ||
![]() |
a586c0781a | ||
![]() |
616d93cb18 | ||
![]() |
73d9cb6d58 | ||
![]() |
9846e8b5cf | ||
![]() |
aa66a12dac | ||
![]() |
65ce9b0889 | ||
![]() |
291e311b8a | ||
![]() |
41290f51fd | ||
![]() |
a11c898e2c | ||
![]() |
9c921183ab | ||
![]() |
b978396a38 | ||
![]() |
c6aa04e986 | ||
![]() |
6c17b8bd87 | ||
![]() |
835a35c6a8 | ||
![]() |
cac32f660c | ||
![]() |
8e70004bf2 | ||
![]() |
c3a466c392 | ||
![]() |
e076c19e3e | ||
![]() |
35b717756d | ||
![]() |
c14486306e | ||
![]() |
c2ef25c377 | ||
![]() |
b7164ef200 | ||
![]() |
f94a366d51 | ||
![]() |
286a04b5ef | ||
![]() |
1209295a8c | ||
![]() |
037b019d4d | ||
![]() |
7a1d788f2a | ||
![]() |
87d9a8cd95 | ||
![]() |
f637d7f617 | ||
![]() |
a4b9a7c6fb | ||
![]() |
9f01155cb7 | ||
![]() |
08e8a48138 | ||
![]() |
551c3b9fb6 | ||
![]() |
2258cb7096 | ||
![]() |
6d61841cf3 | ||
![]() |
c65508d288 | ||
![]() |
2c3f582672 | ||
![]() |
f46ba75771 | ||
![]() |
0ce5f2b6ca | ||
![]() |
110057c294 | ||
![]() |
7553d3c5f4 | ||
![]() |
317976b34a | ||
![]() |
6ad423567f | ||
![]() |
d497158856 | ||
![]() |
f4cada5fa1 | ||
![]() |
352f0ad09c | ||
![]() |
ff1a9c1570 | ||
![]() |
fa811a39a2 | ||
![]() |
cf5018be33 | ||
![]() |
8ec027f9d4 | ||
![]() |
f28428e677 | ||
![]() |
294084bec5 | ||
![]() |
4349907627 | ||
![]() |
f7cef24a83 | ||
![]() |
2774f99b15 | ||
![]() |
bc630fc445 | ||
![]() |
895cf16d33 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@
|
|||||||
/app/prodMainnet
|
/app/prodMainnet
|
||||||
/app/alphaStagenet
|
/app/alphaStagenet
|
||||||
/app/prodStagenet
|
/app/prodStagenet
|
||||||
|
/app/.cxx
|
||||||
|
@@ -155,6 +155,18 @@ add_library(net STATIC IMPORTED)
|
|||||||
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
||||||
|
|
||||||
|
add_library(hardforks STATIC IMPORTED)
|
||||||
|
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libhardforks.a)
|
||||||
|
|
||||||
|
add_library(randomx STATIC IMPORTED)
|
||||||
|
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librandomx.a)
|
||||||
|
|
||||||
|
add_library(rpc_base STATIC IMPORTED)
|
||||||
|
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librpc_base.a)
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# System
|
# System
|
||||||
#############
|
#############
|
||||||
@@ -188,6 +200,9 @@ target_link_libraries( monerujo
|
|||||||
device_trezor
|
device_trezor
|
||||||
multisig
|
multisig
|
||||||
version
|
version
|
||||||
|
randomx
|
||||||
|
hardforks
|
||||||
|
rpc_base
|
||||||
|
|
||||||
boost_chrono
|
boost_chrono
|
||||||
boost_date_time
|
boost_date_time
|
||||||
|
@@ -2,14 +2,13 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
buildToolsVersion '28.0.3'
|
buildToolsVersion '29.0.2'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 179
|
versionCode 405
|
||||||
versionName "1.11.9 'Chernushka'"
|
versionName "1.14.5 'On Board'"
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
@@ -93,6 +92,11 @@ android {
|
|||||||
outputFileName = "$rootProject.ext.apkName-" + v + "_" + abiName + ".apk"
|
outputFileName = "$rootProject.ext.apkName-" + v + "_" + abiName + ".apk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -102,6 +106,7 @@ dependencies {
|
|||||||
implementation "com.android.support:recyclerview-v7:$rootProject.ext.supportVersion"
|
implementation "com.android.support:recyclerview-v7:$rootProject.ext.supportVersion"
|
||||||
implementation "com.android.support:cardview-v7:$rootProject.ext.supportVersion"
|
implementation "com.android.support:cardview-v7:$rootProject.ext.supportVersion"
|
||||||
implementation "com.android.support:swiperefreshlayout:$rootProject.ext.supportVersion"
|
implementation "com.android.support:swiperefreshlayout:$rootProject.ext.supportVersion"
|
||||||
|
implementation "com.android.support.constraint:constraint-layout:$rootProject.ext.constraintVersion"
|
||||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||||
|
|
||||||
implementation "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
|
implementation "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
|
||||||
@@ -124,5 +129,4 @@ dependencies {
|
|||||||
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
||||||
testImplementation 'org.json:json:20180813'
|
testImplementation 'org.json:json:20180813'
|
||||||
testImplementation 'net.jodah:concurrentunit:0.4.4'
|
testImplementation 'net.jodah:concurrentunit:0.4.4'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,24 +20,27 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/MyMaterialTheme"
|
android:theme="@style/MyMaterialTheme"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true">
|
||||||
|
<activity android:name=".MainActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:screenOrientation="portrait">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".WalletActivity"
|
android:name=".WalletActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/wallet_activity_name"
|
android:label="@string/wallet_activity_name"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="behind" />
|
android:screenOrientation="behind" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:screenOrientation="locked">
|
android:screenOrientation="locked">
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@@ -62,6 +65,10 @@
|
|||||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||||
android:resource="@xml/usb_device_filter" />
|
android:resource="@xml/usb_device_filter" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".onboarding.OnBoardingActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:screenOrientation="portrait"/>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.WalletService"
|
android:name=".service.WalletService"
|
||||||
@@ -79,4 +86,4 @@
|
|||||||
android:resource="@xml/filepaths" />
|
android:resource="@xml/filepaths" />
|
||||||
</provider>
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,8 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const char* const MONERO_VERSION; // the actual monero core version
|
||||||
|
|
||||||
// from monero-core crypto/hash-ops.h - avoid #including monero code here
|
// from monero-core crypto/hash-ops.h - avoid #including monero code here
|
||||||
enum {
|
enum {
|
||||||
HASH_SIZE = 32,
|
HASH_SIZE = 32,
|
||||||
|
@@ -46,8 +46,12 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
|||||||
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
||||||
for (UsbDevice device : deviceList.values()) {
|
for (UsbDevice device : deviceList.values()) {
|
||||||
Timber.d("%04X:%04X %s, %s", device.getVendorId(), device.getProductId(), device.getManufacturerName(), device.getProductName());
|
Timber.d("%04X:%04X %s, %s", device.getVendorId(), device.getProductId(), device.getManufacturerName(), device.getProductName());
|
||||||
if ((device.getVendorId() == VID) && (device.getProductId() == PID_HID)) {
|
if (device.getVendorId() == VID) {
|
||||||
return device;
|
final int deviceProductId = device.getProductId();
|
||||||
|
for (int pid : PID_HIDS) {
|
||||||
|
if (deviceProductId == pid)
|
||||||
|
return device;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -74,7 +78,7 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final int VID = 0x2C97;
|
private static final int VID = 0x2C97;
|
||||||
private static final int PID_HID = 0x0001;
|
private static final int[] PID_HIDS = {0x0001, 0x0004};
|
||||||
|
|
||||||
private UsbDeviceConnection connection;
|
private UsbDeviceConnection connection;
|
||||||
private UsbInterface dongleInterface;
|
private UsbInterface dongleInterface;
|
||||||
|
@@ -79,6 +79,23 @@ public class GenerateFragment extends Fragment {
|
|||||||
|
|
||||||
private String type = null;
|
private String type = null;
|
||||||
|
|
||||||
|
private void clearErrorOnTextEntry(final TextInputLayout textInputLayout) {
|
||||||
|
textInputLayout.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
textInputLayout.setError(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
@@ -110,6 +127,23 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clearErrorOnTextEntry(etWalletName);
|
||||||
|
|
||||||
|
etWalletPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
checkPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
etWalletMnemonic.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
etWalletMnemonic.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
@@ -118,6 +152,8 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clearErrorOnTextEntry(etWalletMnemonic);
|
||||||
|
|
||||||
etWalletAddress.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
etWalletAddress.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
@@ -126,6 +162,8 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clearErrorOnTextEntry(etWalletAddress);
|
||||||
|
|
||||||
etWalletViewKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
etWalletViewKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
@@ -134,6 +172,8 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clearErrorOnTextEntry(etWalletViewKey);
|
||||||
|
|
||||||
etWalletSpendKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
etWalletSpendKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
@@ -142,6 +182,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clearErrorOnTextEntry(etWalletSpendKey);
|
||||||
|
|
||||||
Helper.showKeyboard(getActivity());
|
Helper.showKeyboard(getActivity());
|
||||||
|
|
||||||
@@ -310,21 +351,6 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
etWalletPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable editable) {
|
|
||||||
checkPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
etWalletName.requestFocus();
|
etWalletName.requestFocus();
|
||||||
initZxcvbn();
|
initZxcvbn();
|
||||||
|
|
||||||
@@ -412,7 +438,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
height = RestoreHeight.getInstance().getHeight(parser.parse(restoreHeight));
|
||||||
} catch (ParseException ex) {
|
} catch (ParseException ex) {
|
||||||
}
|
}
|
||||||
if (height <= 0)
|
if ((height <= 0) && (restoreHeight.length() == 8))
|
||||||
try {
|
try {
|
||||||
// is it a date without dashes?
|
// is it a date without dashes?
|
||||||
SimpleDateFormat parser = new SimpleDateFormat("yyyyMMdd");
|
SimpleDateFormat parser = new SimpleDateFormat("yyyyMMdd");
|
||||||
@@ -682,8 +708,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
if (Helper.preventScreenshot()) {
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
|
||||||
ledgerDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
ledgerDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -55,6 +55,8 @@ import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
|||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class GenerateReviewFragment extends Fragment {
|
public class GenerateReviewFragment extends Fragment {
|
||||||
@@ -72,6 +74,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
private TextView tvWalletPassword;
|
private TextView tvWalletPassword;
|
||||||
private TextView tvWalletAddress;
|
private TextView tvWalletAddress;
|
||||||
private TextView tvWalletMnemonic;
|
private TextView tvWalletMnemonic;
|
||||||
|
private TextView tvWalletHeight;
|
||||||
private TextView tvWalletViewKey;
|
private TextView tvWalletViewKey;
|
||||||
private TextView tvWalletSpendKey;
|
private TextView tvWalletSpendKey;
|
||||||
private ImageButton bCopyAddress;
|
private ImageButton bCopyAddress;
|
||||||
@@ -99,6 +102,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
tvWalletViewKey = view.findViewById(R.id.tvWalletViewKey);
|
tvWalletViewKey = view.findViewById(R.id.tvWalletViewKey);
|
||||||
tvWalletSpendKey = view.findViewById(R.id.tvWalletSpendKey);
|
tvWalletSpendKey = view.findViewById(R.id.tvWalletSpendKey);
|
||||||
tvWalletMnemonic = view.findViewById(R.id.tvWalletMnemonic);
|
tvWalletMnemonic = view.findViewById(R.id.tvWalletMnemonic);
|
||||||
|
tvWalletHeight = view.findViewById(R.id.tvWalletHeight);
|
||||||
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
||||||
bAdvancedInfo = view.findViewById(R.id.bAdvancedInfo);
|
bAdvancedInfo = view.findViewById(R.id.bAdvancedInfo);
|
||||||
llAdvancedInfo = view.findViewById(R.id.llAdvancedInfo);
|
llAdvancedInfo = view.findViewById(R.id.llAdvancedInfo);
|
||||||
@@ -188,6 +192,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||||
String name;
|
String name;
|
||||||
String address;
|
String address;
|
||||||
|
long height;
|
||||||
String seed;
|
String seed;
|
||||||
String viewKey;
|
String viewKey;
|
||||||
String spendKey;
|
String spendKey;
|
||||||
@@ -232,6 +237,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
address = wallet.getAddress();
|
address = wallet.getAddress();
|
||||||
|
height = wallet.getRestoreHeight();
|
||||||
seed = wallet.getSeed();
|
seed = wallet.getSeed();
|
||||||
switch (wallet.getDeviceType()) {
|
switch (wallet.getDeviceType()) {
|
||||||
case Device_Ledger:
|
case Device_Ledger:
|
||||||
@@ -264,6 +270,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
llPassword.setVisibility(View.VISIBLE);
|
llPassword.setVisibility(View.VISIBLE);
|
||||||
tvWalletPassword.setText(getPassword());
|
tvWalletPassword.setText(getPassword());
|
||||||
tvWalletAddress.setText(address);
|
tvWalletAddress.setText(address);
|
||||||
|
tvWalletHeight.setText(NumberFormat.getInstance().format(height));
|
||||||
if (!seed.isEmpty()) {
|
if (!seed.isEmpty()) {
|
||||||
llMnemonic.setVisibility(View.VISIBLE);
|
llMnemonic.setVisibility(View.VISIBLE);
|
||||||
tvWalletMnemonic.setText(seed);
|
tvWalletMnemonic.setText(seed);
|
||||||
@@ -288,6 +295,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
} else {
|
} else {
|
||||||
// TODO show proper error message and/or end the fragment?
|
// TODO show proper error message and/or end the fragment?
|
||||||
tvWalletAddress.setText(walletStatus.toString());
|
tvWalletAddress.setText(walletStatus.toString());
|
||||||
|
tvWalletHeight.setText(walletStatus.toString());
|
||||||
tvWalletMnemonic.setText(walletStatus.toString());
|
tvWalletMnemonic.setText(walletStatus.toString());
|
||||||
tvWalletViewKey.setText(walletStatus.toString());
|
tvWalletViewKey.setText(walletStatus.toString());
|
||||||
tvWalletSpendKey.setText(walletStatus.toString());
|
tvWalletSpendKey.setText(walletStatus.toString());
|
||||||
@@ -622,8 +630,8 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
if (Helper.preventScreenshot()) {
|
||||||
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -315,10 +315,14 @@ public class LoginActivity extends BaseActivity
|
|||||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||||
Helper.promptPassword(LoginActivity.this, walletName, true, new Helper.PasswordAction() {
|
Helper.promptPassword(LoginActivity.this, walletName, true, new Helper.PasswordAction() {
|
||||||
@Override
|
@Override
|
||||||
public void action(String walletName, String password, boolean fingerprintUsed) {
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
if (checkDevice(walletName, password))
|
if (checkDevice(walletName, password))
|
||||||
startDetails(walletFile, password, GenerateReviewFragment.VIEW_TYPE_DETAILS);
|
startDetails(walletFile, password, GenerateReviewFragment.VIEW_TYPE_DETAILS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else { // this cannot really happen as we prefilter choices
|
} else { // this cannot really happen as we prefilter choices
|
||||||
Timber.e("Wallet missing: %s", walletName);
|
Timber.e("Wallet missing: %s", walletName);
|
||||||
@@ -348,10 +352,14 @@ public class LoginActivity extends BaseActivity
|
|||||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||||
Helper.promptPassword(LoginActivity.this, walletName, false, new Helper.PasswordAction() {
|
Helper.promptPassword(LoginActivity.this, walletName, false, new Helper.PasswordAction() {
|
||||||
@Override
|
@Override
|
||||||
public void action(String walletName, String password, boolean fingerprintUsed) {
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
if (checkDevice(walletName, password))
|
if (checkDevice(walletName, password))
|
||||||
startReceive(walletFile, password);
|
startReceive(walletFile, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else { // this cannot really happen as we prefilter choices
|
} else { // this cannot really happen as we prefilter choices
|
||||||
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
||||||
@@ -940,8 +948,9 @@ public class LoginActivity extends BaseActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean createWallet(File aFile, String password) {
|
public boolean createWallet(File aFile, String password) {
|
||||||
NodeInfo currentNode = getNode();
|
NodeInfo currentNode = getNode();
|
||||||
|
// get it from the connected node if we have one, and go back ca. 4 days
|
||||||
final long restoreHeight =
|
final long restoreHeight =
|
||||||
(currentNode != null) ? currentNode.getHeight() - 20 : -1;
|
(currentNode != null) ? currentNode.getHeight() - 2000 : -1;
|
||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
||||||
return checkAndCloseWallet(newWallet);
|
return checkAndCloseWallet(newWallet);
|
||||||
@@ -1305,10 +1314,15 @@ public class LoginActivity extends BaseActivity
|
|||||||
Helper.promptPassword(LoginActivity.this, walletName, false,
|
Helper.promptPassword(LoginActivity.this, walletName, false,
|
||||||
new Helper.PasswordAction() {
|
new Helper.PasswordAction() {
|
||||||
@Override
|
@Override
|
||||||
public void action(String walletName, String password, boolean fingerprintUsed) {
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
if (checkDevice(walletName, password))
|
if (checkDevice(walletName, password))
|
||||||
startWallet(walletName, password, fingerprintUsed, streetmode);
|
startWallet(walletName, password, fingerprintUsed, streetmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
} else { // this cannot really happen as we prefilter choices
|
} else { // this cannot really happen as we prefilter choices
|
||||||
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
||||||
@@ -1359,17 +1373,30 @@ public class LoginActivity extends BaseActivity
|
|||||||
if (Ledger.ENABLED)
|
if (Ledger.ENABLED)
|
||||||
try {
|
try {
|
||||||
Ledger.connect(usbManager, usbDevice);
|
Ledger.connect(usbManager, usbDevice);
|
||||||
registerDetachReceiver();
|
if (!Ledger.check()) {
|
||||||
onLedgerAction();
|
Ledger.disconnect();
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Toast.makeText(LoginActivity.this,
|
Toast.makeText(LoginActivity.this,
|
||||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
getString(R.string.toast_ledger_start_app, usbDevice.getProductName()),
|
||||||
Toast.LENGTH_SHORT)
|
Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
registerDetachReceiver();
|
||||||
|
onLedgerAction();
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(LoginActivity.this,
|
||||||
|
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
||||||
|
Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -439,10 +439,13 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
}
|
}
|
||||||
Collections.sort(nodesToTest, NodeInfo.BestNodeComparator);
|
Collections.sort(nodesToTest, NodeInfo.BestNodeComparator);
|
||||||
NodeInfo bestNode = nodesToTest.get(0);
|
NodeInfo bestNode = nodesToTest.get(0);
|
||||||
if (bestNode.isValid())
|
if (bestNode.isValid()) {
|
||||||
|
activityCallback.setNode(bestNode);
|
||||||
return bestNode;
|
return bestNode;
|
||||||
else
|
} else {
|
||||||
|
activityCallback.setNode(null);
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -450,7 +453,6 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
if (!isAdded()) return;
|
if (!isAdded()) return;
|
||||||
pbNode.setVisibility(View.INVISIBLE);
|
pbNode.setVisibility(View.INVISIBLE);
|
||||||
llNode.setVisibility(View.VISIBLE);
|
llNode.setVisibility(View.VISIBLE);
|
||||||
activityCallback.setNode(result);
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
Timber.d("found a good node %s", result.toString());
|
Timber.d("found a good node %s", result.toString());
|
||||||
showNode(result);
|
showNode(result);
|
||||||
|
38
app/src/main/java/com/m2049r/xmrwallet/MainActivity.java
Normal file
38
app/src/main/java/com/m2049r/xmrwallet/MainActivity.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 EarlOfEgo, m2049r
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.onboarding.OnBoardingActivity;
|
||||||
|
import com.m2049r.xmrwallet.onboarding.OnBoardingManager;
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (OnBoardingManager.shouldShowOnBoarding(getApplicationContext())) {
|
||||||
|
startActivity(new Intent(this, OnBoardingActivity.class));
|
||||||
|
} else {
|
||||||
|
startActivity(new Intent(this, LoginActivity.class));
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
@@ -266,6 +266,7 @@ public class NodeFragment extends Fragment
|
|||||||
seedList.add(new NodeInfo(new InetSocketAddress("198.74.231.92", 18080)));
|
seedList.add(new NodeInfo(new InetSocketAddress("198.74.231.92", 18080)));
|
||||||
seedList.add(new NodeInfo(new InetSocketAddress("195.154.123.123", 18080)));
|
seedList.add(new NodeInfo(new InetSocketAddress("195.154.123.123", 18080)));
|
||||||
seedList.add(new NodeInfo(new InetSocketAddress("212.83.172.165", 18080)));
|
seedList.add(new NodeInfo(new InetSocketAddress("212.83.172.165", 18080)));
|
||||||
|
seedList.add(new NodeInfo(new InetSocketAddress("192.110.160.146", 18080)));
|
||||||
d.seedPeers(seedList);
|
d.seedPeers(seedList);
|
||||||
d.awaitTermination(NODES_TO_FIND);
|
d.awaitTermination(NODES_TO_FIND);
|
||||||
}
|
}
|
||||||
@@ -506,8 +507,8 @@ public class NodeFragment extends Fragment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
if (Helper.preventScreenshot()) {
|
||||||
editDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
editDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ import android.os.Bundle;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||||
|
|
||||||
import static android.view.WindowManager.LayoutParams;
|
import static android.view.WindowManager.LayoutParams;
|
||||||
@@ -30,8 +31,7 @@ public abstract class SecureActivity extends AppCompatActivity {
|
|||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
if (Helper.preventScreenshot()) {
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
|
||||||
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -88,7 +88,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
private ActionBarDrawerToggle drawerToggle;
|
private ActionBarDrawerToggle drawerToggle;
|
||||||
|
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
private boolean needVerifyIdentity;
|
|
||||||
private boolean requestStreetMode = false;
|
private boolean requestStreetMode = false;
|
||||||
|
|
||||||
private String password;
|
private String password;
|
||||||
@@ -142,7 +141,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
private void enableStreetMode(boolean enable) {
|
private void enableStreetMode(boolean enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
needVerifyIdentity = true;
|
|
||||||
streetMode = getWallet().getDaemonBlockChainHeight();
|
streetMode = getWallet().getDaemonBlockChainHeight();
|
||||||
} else {
|
} else {
|
||||||
streetMode = 0;
|
streetMode = 0;
|
||||||
@@ -151,11 +149,9 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
|
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
|
||||||
if (walletFragment != null) walletFragment.resetDismissedTransactions();
|
if (walletFragment != null) walletFragment.resetDismissedTransactions();
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(() -> {
|
||||||
@Override
|
if (getWallet() != null)
|
||||||
public void run() {
|
|
||||||
updateAccountsBalance();
|
updateAccountsBalance();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +196,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
acquireWakeLock();
|
acquireWakeLock();
|
||||||
String walletId = extras.getString(REQUEST_ID);
|
String walletId = extras.getString(REQUEST_ID);
|
||||||
needVerifyIdentity = extras.getBoolean(REQUEST_FINGERPRINT_USED);
|
|
||||||
// we can set the streetmode height AFTER opening the wallet
|
// we can set the streetmode height AFTER opening the wallet
|
||||||
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
|
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
|
||||||
password = extras.getString(REQUEST_PW);
|
password = extras.getString(REQUEST_PW);
|
||||||
@@ -217,6 +212,20 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
releaseWakeLock();
|
releaseWakeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onWalletRescan() {
|
||||||
|
try {
|
||||||
|
final WalletFragment walletFragment = (WalletFragment)
|
||||||
|
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
|
||||||
|
getWallet().rescanBlockchainAsync();
|
||||||
|
synced = false;
|
||||||
|
walletFragment.unsync();
|
||||||
|
invalidateOptionsMenu();
|
||||||
|
} catch (ClassCastException ex) {
|
||||||
|
Timber.d(ex.getLocalizedMessage());
|
||||||
|
// keep calm and carry on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
Timber.d("onStop()");
|
Timber.d("onStop()");
|
||||||
@@ -243,7 +252,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
MenuItem renameItem = menu.findItem(R.id.action_rename);
|
MenuItem renameItem = menu.findItem(R.id.action_rename);
|
||||||
if (renameItem != null)
|
if (renameItem != null)
|
||||||
renameItem.setVisible(hasWallet() && getWallet().isSynchronized());
|
renameItem.setEnabled(hasWallet() && getWallet().isSynchronized());
|
||||||
MenuItem streetmodeItem = menu.findItem(R.id.action_streetmode);
|
MenuItem streetmodeItem = menu.findItem(R.id.action_streetmode);
|
||||||
if (streetmodeItem != null)
|
if (streetmodeItem != null)
|
||||||
if (isStreetMode()) {
|
if (isStreetMode()) {
|
||||||
@@ -251,12 +260,18 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
} else {
|
} else {
|
||||||
streetmodeItem.setIcon(R.drawable.gunther_24dp);
|
streetmodeItem.setIcon(R.drawable.gunther_24dp);
|
||||||
}
|
}
|
||||||
|
final MenuItem rescanItem = menu.findItem(R.id.action_rescan);
|
||||||
|
if (rescanItem != null)
|
||||||
|
rescanItem.setEnabled(isSynced());
|
||||||
return super.onPrepareOptionsMenu(menu);
|
return super.onPrepareOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
case R.id.action_rescan:
|
||||||
|
onWalletRescan();
|
||||||
|
return true;
|
||||||
case R.id.action_info:
|
case R.id.action_info:
|
||||||
onWalletDetails();
|
onWalletDetails();
|
||||||
return true;
|
return true;
|
||||||
@@ -313,7 +328,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
private void onDisableStreetMode() {
|
private void onDisableStreetMode() {
|
||||||
Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() {
|
Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() {
|
||||||
@Override
|
@Override
|
||||||
public void action(String walletName, String password, boolean fingerprintUsed) {
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -322,6 +337,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,10 +575,9 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
@Override
|
@Override
|
||||||
public boolean onRefreshed(final Wallet wallet, final boolean full) {
|
public boolean onRefreshed(final Wallet wallet, final boolean full) {
|
||||||
Timber.d("onRefreshed()");
|
Timber.d("onRefreshed()");
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(() -> {
|
||||||
public void run() {
|
if (getWallet() != null)
|
||||||
updateAccountsBalance();
|
updateAccountsBalance();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (numAccounts != wallet.getNumAccounts()) {
|
if (numAccounts != wallet.getNumAccounts()) {
|
||||||
numAccounts = wallet.getNumAccounts();
|
numAccounts = wallet.getNumAccounts();
|
||||||
@@ -835,17 +853,16 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
final Bundle extras = new Bundle();
|
final Bundle extras = new Bundle();
|
||||||
extras.putString(GenerateReviewFragment.REQUEST_TYPE, GenerateReviewFragment.VIEW_TYPE_WALLET);
|
extras.putString(GenerateReviewFragment.REQUEST_TYPE, GenerateReviewFragment.VIEW_TYPE_WALLET);
|
||||||
|
|
||||||
if (needVerifyIdentity) {
|
Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() {
|
||||||
Helper.promptPassword(WalletActivity.this, getWallet().getName(), true, new Helper.PasswordAction() {
|
@Override
|
||||||
@Override
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
public void action(String walletName, String password, boolean fingerprintUsed) {
|
replaceFragment(new GenerateReviewFragment(), null, extras);
|
||||||
replaceFragment(new GenerateReviewFragment(), null, extras);
|
}
|
||||||
needVerifyIdentity = false;
|
|
||||||
}
|
@Override
|
||||||
});
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
} else {
|
}
|
||||||
replaceFragment(new GenerateReviewFragment(), null, extras);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DialogInterface.BUTTON_NEGATIVE:
|
case DialogInterface.BUTTON_NEGATIVE:
|
||||||
@@ -983,12 +1000,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
return getWallet().getUnlockedBalance();
|
return getWallet().getUnlockedBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean verifyWalletPassword(String password) {
|
|
||||||
String walletPassword = Helper.getWalletPassword(getApplicationContext(), getWalletName(), password);
|
|
||||||
return walletPassword != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
||||||
|
@@ -50,9 +50,8 @@ import com.m2049r.xmrwallet.widget.Toolbar;
|
|||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -114,9 +113,12 @@ public class WalletFragment extends Fragment
|
|||||||
ivSynced = view.findViewById(R.id.ivSynced);
|
ivSynced = view.findViewById(R.id.ivSynced);
|
||||||
|
|
||||||
sCurrency = view.findViewById(R.id.sCurrency);
|
sCurrency = view.findViewById(R.id.sCurrency);
|
||||||
ArrayAdapter currencyAdapter = ArrayAdapter.createFromResource(getContext(), R.array.currency, R.layout.item_spinner_balance);
|
List<String> currencies = new ArrayList<>();
|
||||||
currencyAdapter.setDropDownViewResource(R.layout.item_spinner_dropdown_item);
|
currencies.add(Helper.BASE_CRYPTO);
|
||||||
sCurrency.setAdapter(currencyAdapter);
|
currencies.addAll(Arrays.asList(getResources().getStringArray(R.array.currency)));
|
||||||
|
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(getContext(), R.layout.item_spinner_balance, currencies);
|
||||||
|
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
sCurrency.setAdapter(spinnerAdapter);
|
||||||
|
|
||||||
bSend = view.findViewById(R.id.bSend);
|
bSend = view.findViewById(R.id.bSend);
|
||||||
bReceive = view.findViewById(R.id.bReceive);
|
bReceive = view.findViewById(R.id.bReceive);
|
||||||
@@ -220,7 +222,7 @@ public class WalletFragment extends Fragment
|
|||||||
// at this point selection is XMR in case of error
|
// at this point selection is XMR in case of error
|
||||||
String displayB;
|
String displayB;
|
||||||
double amountA = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
double amountA = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||||
if (!Helper.CRYPTO.equals(balanceCurrency)) { // not XMR
|
if (!Helper.BASE_CRYPTO.equals(balanceCurrency)) { // not XMR
|
||||||
double amountB = amountA * balanceRate;
|
double amountB = amountA * balanceRate;
|
||||||
displayB = Helper.getFormattedAmount(amountB, false);
|
displayB = Helper.getFormattedAmount(amountB, false);
|
||||||
} else { // XMR
|
} else { // XMR
|
||||||
@@ -229,7 +231,7 @@ public class WalletFragment extends Fragment
|
|||||||
showBalance(displayB);
|
showBalance(displayB);
|
||||||
}
|
}
|
||||||
|
|
||||||
String balanceCurrency = Helper.CRYPTO;
|
String balanceCurrency = Helper.BASE_CRYPTO;
|
||||||
double balanceRate = 1.0;
|
double balanceRate = 1.0;
|
||||||
|
|
||||||
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
|
private final ExchangeApi exchangeApi = Helper.getExchangeApi();
|
||||||
@@ -245,7 +247,7 @@ public class WalletFragment extends Fragment
|
|||||||
Timber.d(currency);
|
Timber.d(currency);
|
||||||
if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) {
|
if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) {
|
||||||
showExchanging();
|
showExchanging();
|
||||||
exchangeApi.queryExchangeRate(Helper.CRYPTO, currency,
|
exchangeApi.queryExchangeRate(Helper.BASE_CRYPTO, currency,
|
||||||
new ExchangeCallback() {
|
new ExchangeCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(final ExchangeRate exchangeRate) {
|
public void onSuccess(final ExchangeRate exchangeRate) {
|
||||||
@@ -301,10 +303,10 @@ public class WalletFragment extends Fragment
|
|||||||
|
|
||||||
public void exchange(final ExchangeRate exchangeRate) {
|
public void exchange(final ExchangeRate exchangeRate) {
|
||||||
hideExchanging();
|
hideExchanging();
|
||||||
if (!Helper.CRYPTO.equals(exchangeRate.getBaseCurrency())) {
|
if (!Helper.BASE_CRYPTO.equals(exchangeRate.getBaseCurrency())) {
|
||||||
Timber.e("Not XMR");
|
Timber.e("Not XMR");
|
||||||
sCurrency.setSelection(0, true);
|
sCurrency.setSelection(0, true);
|
||||||
balanceCurrency = Helper.CRYPTO;
|
balanceCurrency = Helper.BASE_CRYPTO;
|
||||||
balanceRate = 1.0;
|
balanceRate = 1.0;
|
||||||
} else {
|
} else {
|
||||||
int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency());
|
int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency());
|
||||||
@@ -354,6 +356,15 @@ public class WalletFragment extends Fragment
|
|||||||
if (isVisible()) enableAccountsList(true); //otherwise it is enabled in onResume()
|
if (isVisible()) enableAccountsList(true); //otherwise it is enabled in onResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unsync() {
|
||||||
|
if (!activityCallback.isWatchOnly()) {
|
||||||
|
bSend.setVisibility(View.INVISIBLE);
|
||||||
|
bSend.setEnabled(false);
|
||||||
|
}
|
||||||
|
if (isVisible()) enableAccountsList(false); //otherwise it is enabled in onResume()
|
||||||
|
firstBlock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
boolean walletLoaded = false;
|
boolean walletLoaded = false;
|
||||||
|
|
||||||
public void onLoaded() {
|
public void onLoaded() {
|
||||||
|
@@ -59,42 +59,36 @@ public class BarcodeData {
|
|||||||
final public Asset asset;
|
final public Asset asset;
|
||||||
final public String address;
|
final public String address;
|
||||||
final public String addressName;
|
final public String addressName;
|
||||||
final public String paymentId;
|
|
||||||
final public String amount;
|
final public String amount;
|
||||||
final public String description;
|
final public String description;
|
||||||
final public Security security;
|
final public Security security;
|
||||||
final public String bip70;
|
final public String bip70;
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address) {
|
public BarcodeData(Asset asset, String address) {
|
||||||
this(asset, address, null, null, null, null, Security.NORMAL);
|
this(asset, address, null, null, null, Security.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String amount) {
|
public BarcodeData(Asset asset, String address, String amount) {
|
||||||
this(asset, address, null, null, null, amount, Security.NORMAL);
|
this(asset, address, null, null, amount, Security.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String amount, String description, Security security) {
|
public BarcodeData(Asset asset, String address, String amount, String description, Security security) {
|
||||||
this(asset, address, null, null, description, amount, security);
|
this(asset, address, null, description, amount, security);
|
||||||
}
|
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
|
|
||||||
this(asset, address, null, paymentId, null, amount, Security.NORMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String paymentId, String description, String amount) {
|
public BarcodeData(Asset asset, String address, String paymentId, String description, String amount) {
|
||||||
this(asset, address, null, paymentId, description, amount, Security.NORMAL);
|
this(asset, address, null, description, amount, Security.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String addressName, String paymentId, String description, String amount, Security security) {
|
public BarcodeData(Asset asset, String address, String addressName, String description, String amount, Security security) {
|
||||||
this(asset, address, addressName, null, paymentId, description, amount, security);
|
this(asset, address, addressName, null, description, amount, security);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String addressName, String bip70, String paymentId, String description, String amount, Security security) {
|
public BarcodeData(Asset asset, String address, String addressName, String bip70, String description, String amount, Security security) {
|
||||||
this.asset = asset;
|
this.asset = asset;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.bip70 = bip70;
|
this.bip70 = bip70;
|
||||||
this.addressName = addressName;
|
this.addressName = addressName;
|
||||||
this.paymentId = paymentId;
|
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.security = security;
|
this.security = security;
|
||||||
@@ -110,11 +104,6 @@ public class BarcodeData {
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(BarcodeData.XMR_SCHEME).append(address);
|
sb.append(BarcodeData.XMR_SCHEME).append(address);
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if ((paymentId != null) && !paymentId.isEmpty()) {
|
|
||||||
sb.append("?");
|
|
||||||
first = false;
|
|
||||||
sb.append(BarcodeData.XMR_PAYMENTID).append('=').append(paymentId);
|
|
||||||
}
|
|
||||||
if ((description != null) && !description.isEmpty()) {
|
if ((description != null) && !description.isEmpty()) {
|
||||||
sb.append(first ? "?" : "&");
|
sb.append(first ? "?" : "&");
|
||||||
first = false;
|
first = false;
|
||||||
@@ -185,8 +174,11 @@ public class BarcodeData {
|
|||||||
String address = monero.getPath();
|
String address = monero.getPath();
|
||||||
|
|
||||||
String paymentId = parms.get(XMR_PAYMENTID);
|
String paymentId = parms.get(XMR_PAYMENTID);
|
||||||
// deal with empty payment_id created by non-spec-conforming apps
|
// no support for payment ids!
|
||||||
if ((paymentId != null) && paymentId.isEmpty()) paymentId = null;
|
if (paymentId != null) {
|
||||||
|
Timber.e("no support for payment ids!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String description = parms.get(XMR_DESCRIPTION);
|
String description = parms.get(XMR_DESCRIPTION);
|
||||||
String amount = parms.get(XMR_AMOUNT);
|
String amount = parms.get(XMR_AMOUNT);
|
||||||
@@ -198,10 +190,6 @@ public class BarcodeData {
|
|||||||
return null; // we have an amount but its not a number!
|
return null; // we have an amount but its not a number!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((paymentId != null) && !Wallet.isPaymentIdValid(paymentId)) {
|
|
||||||
Timber.d("paymentId invalid");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Wallet.isAddressValid(address)) {
|
if (!Wallet.isAddressValid(address)) {
|
||||||
Timber.d("address invalid");
|
Timber.d("address invalid");
|
||||||
@@ -267,7 +255,7 @@ public class BarcodeData {
|
|||||||
Timber.d("[%s] is not http url", bip70);
|
Timber.d("[%s] is not http url", bip70);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new BarcodeData(BarcodeData.Asset.BTC, null, null, bip70, null, description, null, Security.NORMAL);
|
return new BarcodeData(BarcodeData.Asset.BTC, null, null, bip70, description, null, Security.NORMAL);
|
||||||
}
|
}
|
||||||
if (!BitcoinAddressValidator.validate(address)) {
|
if (!BitcoinAddressValidator.validate(address)) {
|
||||||
Timber.d("BTC address (%s) invalid", address);
|
Timber.d("BTC address (%s) invalid", address);
|
||||||
|
@@ -235,8 +235,10 @@ public class NodeInfo extends Node {
|
|||||||
String rpcVersion = json.getString("jsonrpc");
|
String rpcVersion = json.getString("jsonrpc");
|
||||||
if (!RPC_VERSION.equals(rpcVersion))
|
if (!RPC_VERSION.equals(rpcVersion))
|
||||||
return false;
|
return false;
|
||||||
final JSONObject header = json.getJSONObject(
|
final JSONObject result = json.getJSONObject("result");
|
||||||
"result").getJSONObject("block_header");
|
if (!result.has("credits")) // introduced in monero v0.15.0
|
||||||
|
return false;
|
||||||
|
final JSONObject header = result.getJSONObject("block_header");
|
||||||
height = header.getLong("height");
|
height = header.getLong("height");
|
||||||
timestamp = header.getLong("timestamp");
|
timestamp = header.getLong("timestamp");
|
||||||
majorVersion = header.getInt("major_version");
|
majorVersion = header.getInt("major_version");
|
||||||
|
@@ -29,19 +29,16 @@ public class TxData implements Parcelable {
|
|||||||
|
|
||||||
public TxData(TxData txData) {
|
public TxData(TxData txData) {
|
||||||
this.dstAddr = txData.dstAddr;
|
this.dstAddr = txData.dstAddr;
|
||||||
this.paymentId = txData.paymentId;
|
|
||||||
this.amount = txData.amount;
|
this.amount = txData.amount;
|
||||||
this.mixin = txData.mixin;
|
this.mixin = txData.mixin;
|
||||||
this.priority = txData.priority;
|
this.priority = txData.priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TxData(String dstAddr,
|
public TxData(String dstAddr,
|
||||||
String paymentId,
|
|
||||||
long amount,
|
long amount,
|
||||||
int mixin,
|
int mixin,
|
||||||
PendingTransaction.Priority priority) {
|
PendingTransaction.Priority priority) {
|
||||||
this.dstAddr = dstAddr;
|
this.dstAddr = dstAddr;
|
||||||
this.paymentId = paymentId;
|
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.mixin = mixin;
|
this.mixin = mixin;
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
@@ -51,10 +48,6 @@ public class TxData implements Parcelable {
|
|||||||
return dstAddr;
|
return dstAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPaymentId() {
|
|
||||||
return paymentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getAmount() {
|
public long getAmount() {
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
@@ -71,10 +64,6 @@ public class TxData implements Parcelable {
|
|||||||
this.dstAddr = dstAddr;
|
this.dstAddr = dstAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaymentId(String paymentId) {
|
|
||||||
this.paymentId = paymentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAmount(long amount) {
|
public void setAmount(long amount) {
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
@@ -96,7 +85,6 @@ public class TxData implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String dstAddr;
|
private String dstAddr;
|
||||||
private String paymentId;
|
|
||||||
private long amount;
|
private long amount;
|
||||||
private int mixin;
|
private int mixin;
|
||||||
private PendingTransaction.Priority priority;
|
private PendingTransaction.Priority priority;
|
||||||
@@ -106,7 +94,6 @@ public class TxData implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
out.writeString(dstAddr);
|
out.writeString(dstAddr);
|
||||||
out.writeString(paymentId);
|
|
||||||
out.writeLong(amount);
|
out.writeLong(amount);
|
||||||
out.writeInt(mixin);
|
out.writeInt(mixin);
|
||||||
out.writeInt(priority.getValue());
|
out.writeInt(priority.getValue());
|
||||||
@@ -125,7 +112,6 @@ public class TxData implements Parcelable {
|
|||||||
|
|
||||||
protected TxData(Parcel in) {
|
protected TxData(Parcel in) {
|
||||||
dstAddr = in.readString();
|
dstAddr = in.readString();
|
||||||
paymentId = in.readString();
|
|
||||||
amount = in.readLong();
|
amount = in.readLong();
|
||||||
mixin = in.readInt();
|
mixin = in.readInt();
|
||||||
priority = PendingTransaction.Priority.fromInteger(in.readInt());
|
priority = PendingTransaction.Priority.fromInteger(in.readInt());
|
||||||
@@ -142,14 +128,12 @@ public class TxData implements Parcelable {
|
|||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append("dstAddr:");
|
sb.append("dstAddr:");
|
||||||
sb.append(dstAddr);
|
sb.append(dstAddr);
|
||||||
sb.append(",paymentId:");
|
|
||||||
sb.append(paymentId);
|
|
||||||
sb.append(",amount:");
|
sb.append(",amount:");
|
||||||
sb.append(amount);
|
sb.append(amount);
|
||||||
sb.append(",mixin:");
|
sb.append(",mixin:");
|
||||||
sb.append(mixin);
|
sb.append(mixin);
|
||||||
sb.append(",priority:");
|
sb.append(",priority:");
|
||||||
sb.append(String.valueOf(priority));
|
sb.append(priority);
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.m2049r.xmrwallet.BuildConfig;
|
import com.m2049r.xmrwallet.BuildConfig;
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -76,8 +77,7 @@ public class ProgressDialog extends AlertDialog {
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
if (Helper.preventScreenshot()) {
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
|
||||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,6 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -86,12 +85,9 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
private TextInputLayout etAddress;
|
private TextInputLayout etAddress;
|
||||||
private TextInputLayout etPaymentId;
|
|
||||||
private TextInputLayout etNotes;
|
private TextInputLayout etNotes;
|
||||||
private Button bPaymentId;
|
|
||||||
private CardView cvScan;
|
private CardView cvScan;
|
||||||
private View tvPaymentIdIntegrated;
|
private View tvPaymentIdIntegrated;
|
||||||
private View llPaymentId;
|
|
||||||
private TextView tvXmrTo;
|
private TextView tvXmrTo;
|
||||||
private View llXmrTo;
|
private View llXmrTo;
|
||||||
private ImageButton bPasteAddress;
|
private ImageButton bPasteAddress;
|
||||||
@@ -114,7 +110,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
View view = inflater.inflate(R.layout.fragment_send_address, container, false);
|
View view = inflater.inflate(R.layout.fragment_send_address, container, false);
|
||||||
|
|
||||||
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
|
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
|
||||||
llPaymentId = view.findViewById(R.id.llPaymentId);
|
|
||||||
llXmrTo = view.findViewById(R.id.llXmrTo);
|
llXmrTo = view.findViewById(R.id.llXmrTo);
|
||||||
tvXmrTo = view.findViewById(R.id.tvXmrTo);
|
tvXmrTo = view.findViewById(R.id.tvXmrTo);
|
||||||
tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto)));
|
tvXmrTo.setText(Html.fromHtml(getString(R.string.info_xmrto)));
|
||||||
@@ -140,28 +135,12 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
next = null;
|
next = null;
|
||||||
} else {
|
} else {
|
||||||
// maybe a bip72 or 70 URI
|
// maybe a bip72 or 70 URI
|
||||||
String bip70 = PaymentProtocolHelper.getBip70(enteredAddress);
|
final String bip70 = PaymentProtocolHelper.getBip70(enteredAddress);
|
||||||
if (bip70 != null) {
|
if (bip70 != null) {
|
||||||
// looks good - resolve through xmr.to
|
// looks good - resolve through xmr.to
|
||||||
processBip70(bip70);
|
processBip70(bip70);
|
||||||
next = null;
|
|
||||||
} else if (checkAddress()) {
|
|
||||||
if (llPaymentId.getVisibility() == View.VISIBLE) {
|
|
||||||
next = etPaymentId;
|
|
||||||
} else {
|
|
||||||
next = etNotes;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (next != null) {
|
|
||||||
final View focus = next;
|
|
||||||
etAddress.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
focus.requestFocus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -174,8 +153,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
etAddress.setError(null);
|
etAddress.setError(null);
|
||||||
if (isIntegratedAddress()) {
|
if (isIntegratedAddress()) {
|
||||||
Timber.d("isIntegratedAddress");
|
Timber.d("isIntegratedAddress");
|
||||||
etPaymentId.getEditText().getText().clear();
|
etAddress.setError(getString(R.string.info_paymentid_integrated));
|
||||||
llPaymentId.setVisibility(View.INVISIBLE);
|
|
||||||
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
|
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
|
||||||
llXmrTo.setVisibility(View.INVISIBLE);
|
llXmrTo.setVisibility(View.INVISIBLE);
|
||||||
sendListener.setMode(SendFragment.Mode.XMR);
|
sendListener.setMode(SendFragment.Mode.XMR);
|
||||||
@@ -184,7 +162,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
setBtcMode();
|
setBtcMode();
|
||||||
} else {
|
} else {
|
||||||
Timber.d("isStandardAddress or other");
|
Timber.d("isStandardAddress or other");
|
||||||
llPaymentId.setVisibility(View.VISIBLE);
|
|
||||||
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
|
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
|
||||||
llXmrTo.setVisibility(View.INVISIBLE);
|
llXmrTo.setVisibility(View.INVISIBLE);
|
||||||
sendListener.setMode(SendFragment.Mode.XMR);
|
sendListener.setMode(SendFragment.Mode.XMR);
|
||||||
@@ -208,47 +185,21 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
if (clip == null) return;
|
if (clip == null) return;
|
||||||
// clean it up
|
// clean it up
|
||||||
final String address = clip.replaceAll("[^0-9A-Z-a-z]", "");
|
final String address = clip.replaceAll("[^0-9A-Z-a-z]", "");
|
||||||
if (Wallet.isAddressValid(address) || BitcoinAddressValidator.validate(address))
|
if (Wallet.isAddressValid(address) || BitcoinAddressValidator.validate(address)) {
|
||||||
etAddress.getEditText().setText(address);
|
final EditText et = etAddress.getEditText();
|
||||||
else
|
et.setText(address);
|
||||||
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
et.setSelection(et.getText().length());
|
||||||
}
|
etAddress.requestFocus();
|
||||||
});
|
} else {
|
||||||
|
final String bip70 = PaymentProtocolHelper.getBip70(clip);
|
||||||
etPaymentId = view.findViewById(R.id.etPaymentId);
|
if (bip70 != null) {
|
||||||
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
final EditText et = etAddress.getEditText();
|
||||||
etPaymentId.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
et.setText(clip);
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
et.setSelection(et.getText().length());
|
||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
processBip70(bip70);
|
||||||
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
} else
|
||||||
if (checkPaymentId()) {
|
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
||||||
etNotes.requestFocus();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
etPaymentId.getEditText().addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable editable) {
|
|
||||||
etPaymentId.setError(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bPaymentId = view.findViewById(R.id.bPaymentId);
|
|
||||||
bPaymentId.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
etPaymentId.getEditText().setText((Wallet.generatePaymentId()));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -259,7 +210,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
||||||
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -277,7 +227,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
etDummy = view.findViewById(R.id.etDummy);
|
etDummy = view.findViewById(R.id.etDummy);
|
||||||
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
|
|
||||||
View tvNfc = view.findViewById(R.id.tvNfc);
|
View tvNfc = view.findViewById(R.id.tvNfc);
|
||||||
NfcManager manager = (NfcManager) getContext().getSystemService(Context.NFC_SERVICE);
|
NfcManager manager = (NfcManager) getContext().getSystemService(Context.NFC_SERVICE);
|
||||||
@@ -289,8 +238,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private void setBtcMode() {
|
private void setBtcMode() {
|
||||||
Timber.d("setBtcMode");
|
Timber.d("setBtcMode");
|
||||||
etPaymentId.getEditText().getText().clear();
|
|
||||||
llPaymentId.setVisibility(View.INVISIBLE);
|
|
||||||
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
|
tvPaymentIdIntegrated.setVisibility(View.INVISIBLE);
|
||||||
llXmrTo.setVisibility(View.VISIBLE);
|
llXmrTo.setVisibility(View.VISIBLE);
|
||||||
sendListener.setMode(SendFragment.Mode.BTC);
|
sendListener.setMode(SendFragment.Mode.BTC);
|
||||||
@@ -345,7 +292,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
final BarcodeData barcodeData =
|
final BarcodeData barcodeData =
|
||||||
new BarcodeData(BarcodeData.Asset.BTC, address, null,
|
new BarcodeData(BarcodeData.Asset.BTC, address, null,
|
||||||
resolvedBip70, null, null, String.valueOf(amount),
|
resolvedBip70, null, String.valueOf(amount),
|
||||||
BarcodeData.Security.BIP70);
|
BarcodeData.Security.BIP70);
|
||||||
etNotes.post(new Runnable() {
|
etNotes.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -406,22 +353,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
return BitcoinAddressValidator.validate(address);
|
return BitcoinAddressValidator.validate(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPaymentId() {
|
|
||||||
String paymentId = etPaymentId.getEditText().getText().toString();
|
|
||||||
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
|
||||||
if (!ok) {
|
|
||||||
etPaymentId.setError(getString(R.string.receive_paymentid_invalid));
|
|
||||||
} else {
|
|
||||||
if (!paymentId.isEmpty() && isIntegratedAddress()) {
|
|
||||||
ok = false;
|
|
||||||
etPaymentId.setError(getString(R.string.receive_integrated_paymentid_invalid));
|
|
||||||
} else {
|
|
||||||
etPaymentId.setError(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shakeAddress() {
|
private void shakeAddress() {
|
||||||
etAddress.startAnimation(Helper.getShakeAnimation(getContext()));
|
etAddress.startAnimation(Helper.getShakeAnimation(getContext()));
|
||||||
}
|
}
|
||||||
@@ -444,11 +375,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkPaymentId()) {
|
|
||||||
etPaymentId.startAnimation(Helper.getShakeAnimation(getContext()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
TxData txData = sendListener.getTxData();
|
TxData txData = sendListener.getTxData();
|
||||||
if (txData instanceof TxDataBtc) {
|
if (txData instanceof TxDataBtc) {
|
||||||
@@ -462,10 +388,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
((TxDataBtc) txData).setBip70(null);
|
((TxDataBtc) txData).setBip70(null);
|
||||||
}
|
}
|
||||||
txData.setDestinationAddress(null);
|
txData.setDestinationAddress(null);
|
||||||
txData.setPaymentId("");
|
|
||||||
} else {
|
} else {
|
||||||
txData.setDestinationAddress(etAddress.getEditText().getText().toString());
|
txData.setDestinationAddress(etAddress.getEditText().getText().toString());
|
||||||
txData.setPaymentId(etPaymentId.getEditText().getText().toString());
|
|
||||||
}
|
}
|
||||||
txData.setUserNotes(new UserNotes(etNotes.getEditText().getText().toString()));
|
txData.setUserNotes(new UserNotes(etNotes.getEditText().getText().toString()));
|
||||||
txData.setPriority(PendingTransaction.Priority.Priority_Default);
|
txData.setPriority(PendingTransaction.Priority.Priority_Default);
|
||||||
@@ -528,14 +452,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
etAddress.setError(null);
|
etAddress.setError(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
String scannedPaymentId = barcodeData.paymentId;
|
|
||||||
if (scannedPaymentId != null) {
|
|
||||||
etPaymentId.getEditText().setText(scannedPaymentId);
|
|
||||||
checkPaymentId();
|
|
||||||
} else {
|
|
||||||
etPaymentId.getEditText().getText().clear();
|
|
||||||
etPaymentId.setError(null);
|
|
||||||
}
|
|
||||||
String scannedNotes = barcodeData.description;
|
String scannedNotes = barcodeData.description;
|
||||||
if (scannedNotes != null) {
|
if (scannedNotes != null) {
|
||||||
etNotes.getEditText().setText(scannedNotes);
|
etNotes.getEditText().setText(scannedNotes);
|
||||||
@@ -551,7 +467,6 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
|||||||
public void onResumeFragment() {
|
public void onResumeFragment() {
|
||||||
super.onResumeFragment();
|
super.onResumeFragment();
|
||||||
Timber.d("onResumeFragment()");
|
Timber.d("onResumeFragment()");
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,8 +21,6 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
@@ -30,8 +28,7 @@ import com.m2049r.xmrwallet.data.BarcodeData;
|
|||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.widget.ExchangeTextView;
|
import com.m2049r.xmrwallet.widget.ExchangeEditText;
|
||||||
import com.m2049r.xmrwallet.widget.NumberPadView;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -59,8 +56,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TextView tvFunds;
|
private TextView tvFunds;
|
||||||
private ExchangeTextView evAmount;
|
private ExchangeEditText etAmount;
|
||||||
private View llAmount;
|
|
||||||
private View rlSweep;
|
private View rlSweep;
|
||||||
private ImageButton ibSweep;
|
private ImageButton ibSweep;
|
||||||
|
|
||||||
@@ -75,12 +71,9 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
View view = inflater.inflate(R.layout.fragment_send_amount, container, false);
|
View view = inflater.inflate(R.layout.fragment_send_amount, container, false);
|
||||||
|
|
||||||
tvFunds = view.findViewById(R.id.tvFunds);
|
tvFunds = view.findViewById(R.id.tvFunds);
|
||||||
|
etAmount = view.findViewById(R.id.etAmount);
|
||||||
evAmount = view.findViewById(R.id.evAmount);
|
|
||||||
((NumberPadView) view.findViewById(R.id.numberPad)).setListener(evAmount);
|
|
||||||
|
|
||||||
rlSweep = view.findViewById(R.id.rlSweep);
|
rlSweep = view.findViewById(R.id.rlSweep);
|
||||||
llAmount = view.findViewById(R.id.llAmount);
|
|
||||||
view.findViewById(R.id.ivSweep).setOnClickListener(new View.OnClickListener() {
|
view.findViewById(R.id.ivSweep).setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@@ -97,8 +90,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Helper.hideKeyboard(getActivity());
|
etAmount.requestFocus();
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,11 +99,11 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
private void sweepAll(boolean spendAllMode) {
|
private void sweepAll(boolean spendAllMode) {
|
||||||
if (spendAllMode) {
|
if (spendAllMode) {
|
||||||
ibSweep.setVisibility(View.INVISIBLE);
|
ibSweep.setVisibility(View.INVISIBLE);
|
||||||
llAmount.setVisibility(View.GONE);
|
etAmount.setVisibility(View.GONE);
|
||||||
rlSweep.setVisibility(View.VISIBLE);
|
rlSweep.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
ibSweep.setVisibility(View.VISIBLE);
|
ibSweep.setVisibility(View.VISIBLE);
|
||||||
llAmount.setVisibility(View.VISIBLE);
|
etAmount.setVisibility(View.VISIBLE);
|
||||||
rlSweep.setVisibility(View.GONE);
|
rlSweep.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
this.spendAllMode = spendAllMode;
|
this.spendAllMode = spendAllMode;
|
||||||
@@ -124,12 +116,12 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
sendListener.getTxData().setAmount(Wallet.SWEEP_ALL);
|
sendListener.getTxData().setAmount(Wallet.SWEEP_ALL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!evAmount.validate(maxFunds)) {
|
if (!etAmount.validate(maxFunds, 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
String xmr = evAmount.getAmount();
|
String xmr = etAmount.getNativeAmount();
|
||||||
if (xmr != null) {
|
if (xmr != null) {
|
||||||
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
|
sendListener.getTxData().setAmount(Wallet.getAmountFromString(xmr));
|
||||||
} else {
|
} else {
|
||||||
@@ -146,7 +138,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
public void onResumeFragment() {
|
public void onResumeFragment() {
|
||||||
super.onResumeFragment();
|
super.onResumeFragment();
|
||||||
Timber.d("onResumeFragment()");
|
Timber.d("onResumeFragment()");
|
||||||
Helper.hideKeyboard(getActivity());
|
Helper.showKeyboard(getActivity());
|
||||||
final long funds = getTotalFunds();
|
final long funds = getTotalFunds();
|
||||||
maxFunds = 1.0 * funds / 1000000000000L;
|
maxFunds = 1.0 * funds / 1000000000000L;
|
||||||
if (!sendListener.getActivityCallback().isStreetMode()) {
|
if (!sendListener.getActivityCallback().isStreetMode()) {
|
||||||
@@ -156,11 +148,11 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
|||||||
tvFunds.setText(getString(R.string.send_available,
|
tvFunds.setText(getString(R.string.send_available,
|
||||||
getString(R.string.unknown_amount)));
|
getString(R.string.unknown_amount)));
|
||||||
}
|
}
|
||||||
// getAmount is null if exchange is in progress
|
// getNativeAmount is null if exchange is in progress
|
||||||
if ((evAmount.getAmount() != null) && evAmount.getAmount().isEmpty()) {
|
if ((etAmount.getNativeAmount() != null) && etAmount.getNativeAmount().isEmpty()) {
|
||||||
final BarcodeData data = sendListener.popBarcodeData();
|
final BarcodeData data = sendListener.popBarcodeData();
|
||||||
if ((data != null) && (data.amount != null)) {
|
if ((data != null) && (data.amount != null)) {
|
||||||
evAmount.setAmount(data.amount);
|
etAmount.setAmount(data.amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,8 +31,8 @@ import com.m2049r.xmrwallet.data.TxDataBtc;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.OkHttpHelper;
|
import com.m2049r.xmrwallet.util.OkHttpHelper;
|
||||||
import com.m2049r.xmrwallet.widget.ExchangeBtcTextView;
|
import com.m2049r.xmrwallet.widget.ExchangeEditText;
|
||||||
import com.m2049r.xmrwallet.widget.NumberPadView;
|
import com.m2049r.xmrwallet.widget.ExchangeOtherEditText;
|
||||||
import com.m2049r.xmrwallet.widget.SendProgressView;
|
import com.m2049r.xmrwallet.widget.SendProgressView;
|
||||||
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
import com.m2049r.xmrwallet.xmrto.XmrToError;
|
||||||
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
import com.m2049r.xmrwallet.xmrto.XmrToException;
|
||||||
@@ -62,8 +62,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TextView tvFunds;
|
private TextView tvFunds;
|
||||||
private ExchangeBtcTextView evAmount;
|
private ExchangeOtherEditText etAmount;
|
||||||
private NumberPadView numberPad;
|
|
||||||
|
|
||||||
private TextView tvXmrToParms;
|
private TextView tvXmrToParms;
|
||||||
private SendProgressView evParams;
|
private SendProgressView evParams;
|
||||||
@@ -86,24 +85,20 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
tvXmrToParms = view.findViewById(R.id.tvXmrToParms);
|
tvXmrToParms = view.findViewById(R.id.tvXmrToParms);
|
||||||
|
|
||||||
evAmount = view.findViewById(R.id.evAmount);
|
etAmount = view.findViewById(R.id.etAmount);
|
||||||
numberPad = view.findViewById(R.id.numberPad);
|
etAmount.requestFocus();
|
||||||
numberPad.setListener(evAmount);
|
|
||||||
|
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onValidateFields() {
|
public boolean onValidateFields() {
|
||||||
if (!evAmount.validate(maxBtc, minBtc)) {
|
if (!etAmount.validate(maxBtc, minBtc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (sendListener != null) {
|
if (sendListener != null) {
|
||||||
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
|
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
|
||||||
String btcString = evAmount.getAmount();
|
String btcString = etAmount.getNativeAmount();
|
||||||
if (btcString != null) {
|
if (btcString != null) {
|
||||||
try {
|
try {
|
||||||
double btc = Double.parseDouble(btcString);
|
double btc = Double.parseDouble(btcString);
|
||||||
@@ -122,10 +117,12 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
private void setBip70Mode() {
|
private void setBip70Mode() {
|
||||||
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
|
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
|
||||||
if (txDataBtc.getBip70() != null) {
|
if (txDataBtc.getBip70() == null) {
|
||||||
numberPad.setVisibility(View.INVISIBLE);
|
etAmount.setEditable(true);
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
} else {
|
} else {
|
||||||
numberPad.setVisibility(View.VISIBLE);
|
etAmount.setEditable(false);
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +138,6 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
public void onResumeFragment() {
|
public void onResumeFragment() {
|
||||||
super.onResumeFragment();
|
super.onResumeFragment();
|
||||||
Timber.d("onResumeFragment()");
|
Timber.d("onResumeFragment()");
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
final long funds = getTotalFunds();
|
final long funds = getTotalFunds();
|
||||||
if (!sendListener.getActivityCallback().isStreetMode()) {
|
if (!sendListener.getActivityCallback().isStreetMode()) {
|
||||||
tvFunds.setText(getString(R.string.send_available,
|
tvFunds.setText(getString(R.string.send_available,
|
||||||
@@ -153,7 +149,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
final BarcodeData data = sendListener.popBarcodeData();
|
final BarcodeData data = sendListener.popBarcodeData();
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
if (data.amount != null) {
|
if (data.amount != null) {
|
||||||
evAmount.setAmount(data.amount);
|
etAmount.setAmount(data.amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setBip70Mode();
|
setBip70Mode();
|
||||||
@@ -171,7 +167,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
getView().post(new Runnable() {
|
getView().post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
evAmount.setRate(1.0d / orderParameters.getPrice());
|
etAmount.setExchangeRate(1.0d / orderParameters.getPrice());
|
||||||
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
||||||
df.setMaximumFractionDigits(6);
|
df.setMaximumFractionDigits(6);
|
||||||
String min = df.format(orderParameters.getLowerLimit());
|
String min = df.format(orderParameters.getLowerLimit());
|
||||||
@@ -211,7 +207,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processOrderParmsError(final Exception ex) {
|
private void processOrderParmsError(final Exception ex) {
|
||||||
evAmount.setRate(0);
|
etAmount.setExchangeRate(0);
|
||||||
orderParameters = null;
|
orderParameters = null;
|
||||||
maxBtc = 0;
|
maxBtc = 0;
|
||||||
minBtc = 0;
|
minBtc = 0;
|
||||||
|
@@ -346,103 +346,16 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void preSend() {
|
public void preSend() {
|
||||||
final Activity activity = getActivity();
|
Helper.promptPassword(getContext(), getActivityCallback().getWalletName(), false, new Helper.PasswordAction() {
|
||||||
View promptsView = getLayoutInflater().inflate(R.layout.prompt_password, null);
|
|
||||||
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
|
|
||||||
alertDialogBuilder.setView(promptsView);
|
|
||||||
|
|
||||||
final TextInputLayout etPassword = promptsView.findViewById(R.id.etPassword);
|
|
||||||
etPassword.setHint(getString(R.string.prompt_send_password));
|
|
||||||
|
|
||||||
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
if (etPassword.getError() != null) {
|
send();
|
||||||
etPassword.setError(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
public void beforeTextChanged(CharSequence s, int start,
|
bSend.setEnabled(sendCountdown > 0); // allow to try again
|
||||||
int count, int after) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start,
|
|
||||||
int before, int count) {
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
alertDialogBuilder
|
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
|
||||||
if (getActivityCallback().verifyWalletPassword(pass)) {
|
|
||||||
dialog.dismiss();
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
etPassword.setError(getString(R.string.bad_password));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(getString(R.string.label_cancel),
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
dialog.cancel();
|
|
||||||
bSend.setEnabled(sendCountdown > 0); // allow to try again
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final android.app.AlertDialog passwordDialog = alertDialogBuilder.create();
|
|
||||||
passwordDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
|
||||||
@Override
|
|
||||||
public void onShow(DialogInterface dialog) {
|
|
||||||
Button button = ((android.app.AlertDialog) dialog).getButton(android.app.AlertDialog.BUTTON_POSITIVE);
|
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
|
||||||
if (getActivityCallback().verifyWalletPassword(pass)) {
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
passwordDialog.dismiss();
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
etPassword.setError(getString(R.string.bad_password));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Helper.showKeyboard(passwordDialog);
|
|
||||||
|
|
||||||
// accept keyboard "ok"
|
|
||||||
etPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
|
||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
|
||||||
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
|
||||||
if (getActivityCallback().verifyWalletPassword(pass)) {
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
passwordDialog.dismiss();
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
etPassword.setError(getString(R.string.bad_password));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
|
||||||
passwordDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordDialog.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a pending transaction and calls us back with transactionCreated()
|
// creates a pending transaction and calls us back with transactionCreated()
|
||||||
@@ -457,9 +370,8 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
|
|||||||
}
|
}
|
||||||
showProgress(3, getString(R.string.label_send_progress_create_tx));
|
showProgress(3, getString(R.string.label_send_progress_create_tx));
|
||||||
TxData txData = sendListener.getTxData();
|
TxData txData = sendListener.getTxData();
|
||||||
txData.setDestinationAddress(xmrtoStatus.getXmrReceivingAddress());
|
txData.setDestinationAddress(xmrtoStatus.getReceivingSubaddress());
|
||||||
txData.setPaymentId(xmrtoStatus.getXmrRequiredPaymentIdShort());
|
txData.setAmount(Wallet.getAmountFromDouble(xmrtoStatus.getIncomingAmountTotal()));
|
||||||
txData.setAmount(Wallet.getAmountFromDouble(xmrtoStatus.getXmrAmountTotal()));
|
|
||||||
getActivityCallback().onPrepareSend(xmrtoStatus.getUuid(), txData);
|
getActivityCallback().onPrepareSend(xmrtoStatus.getUuid(), txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,22 +485,22 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
|
|||||||
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
NumberFormat df = NumberFormat.getInstance(Locale.US);
|
||||||
df.setMaximumFractionDigits(12);
|
df.setMaximumFractionDigits(12);
|
||||||
String btcAmount = df.format(status.getBtcAmount());
|
String btcAmount = df.format(status.getBtcAmount());
|
||||||
String xmrAmountTotal = df.format(status.getXmrAmountTotal());
|
String xmrAmountTotal = df.format(status.getIncomingAmountTotal());
|
||||||
tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount, btcAmount, xmrAmountTotal));
|
tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount, btcAmount, xmrAmountTotal));
|
||||||
String xmrPriceBtc = df.format(status.getXmrPriceBtc());
|
String xmrPriceBtc = df.format(status.getIncomingPriceBtc());
|
||||||
tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc));
|
tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc));
|
||||||
|
|
||||||
double calcRate = status.getBtcAmount() / status.getXmrPriceBtc();
|
double calcRate = status.getBtcAmount() / status.getIncomingPriceBtc();
|
||||||
Timber.i("Rates: %f / %f", calcRate, status.getXmrPriceBtc());
|
Timber.d("Rates: %f / %f", calcRate, status.getIncomingPriceBtc());
|
||||||
|
|
||||||
tvTxBtcAddress.setText(status.getBtcDestAddress()); // TODO test if this is different?
|
tvTxBtcAddress.setText(status.getBtcDestAddress()); // TODO test if this is different?
|
||||||
|
|
||||||
Timber.i("Expires @ %s, in %s seconds", status.getExpiresAt().toString(), status.getSecondsTillTimeout());
|
Timber.d("Expires @ %s, in %s seconds", status.getExpiresAt().toString(), status.getSecondsTillTimeout());
|
||||||
|
|
||||||
Timber.i("Status = %s", status.getState().toString());
|
Timber.d("Status = %s", status.getState().toString());
|
||||||
tvTxXmrToKey.setText(status.getUuid());
|
tvTxXmrToKey.setText(status.getUuid());
|
||||||
|
|
||||||
Timber.d("AmountRemaining=%f, XmrAmountTotal=%f", status.getXmrAmountRemaining(), status.getXmrAmountTotal());
|
Timber.d("AmountRemaining=%f, XmrAmountTotal=%f", status.getRemainingAmountIncoming(), status.getIncomingAmountTotal());
|
||||||
hideProgress();
|
hideProgress();
|
||||||
startSendTimer();
|
startSendTimer();
|
||||||
prepareSend();
|
prepareSend();
|
||||||
|
@@ -138,12 +138,6 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
btcData = (TxDataBtc) sendListener.getTxData();
|
btcData = (TxDataBtc) sendListener.getTxData();
|
||||||
tvTxAddress.setText(btcData.getDestinationAddress());
|
tvTxAddress.setText(btcData.getDestinationAddress());
|
||||||
String paymentId = btcData.getPaymentId();
|
|
||||||
if ((paymentId != null) && (!paymentId.isEmpty())) {
|
|
||||||
tvTxPaymentId.setText(btcData.getPaymentId());
|
|
||||||
} else {
|
|
||||||
tvTxPaymentId.setText("-");
|
|
||||||
}
|
|
||||||
|
|
||||||
final PendingTx committedTx = sendListener.getCommittedTx();
|
final PendingTx committedTx = sendListener.getCommittedTx();
|
||||||
if (committedTx != null) {
|
if (committedTx != null) {
|
||||||
|
@@ -70,7 +70,6 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TextView tvTxAddress;
|
private TextView tvTxAddress;
|
||||||
private TextView tvTxPaymentId;
|
|
||||||
private TextView tvTxNotes;
|
private TextView tvTxNotes;
|
||||||
private TextView tvTxAmount;
|
private TextView tvTxAmount;
|
||||||
private TextView tvTxFee;
|
private TextView tvTxFee;
|
||||||
@@ -90,7 +89,6 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
|||||||
R.layout.fragment_send_confirm, container, false);
|
R.layout.fragment_send_confirm, container, false);
|
||||||
|
|
||||||
tvTxAddress = view.findViewById(R.id.tvTxAddress);
|
tvTxAddress = view.findViewById(R.id.tvTxAddress);
|
||||||
tvTxPaymentId = view.findViewById(R.id.tvTxPaymentId);
|
|
||||||
tvTxNotes = view.findViewById(R.id.tvTxNotes);
|
tvTxNotes = view.findViewById(R.id.tvTxNotes);
|
||||||
tvTxAmount = view.findViewById(R.id.tvTxAmount);
|
tvTxAmount = view.findViewById(R.id.tvTxAmount);
|
||||||
tvTxFee = view.findViewById(R.id.tvTxFee);
|
tvTxFee = view.findViewById(R.id.tvTxFee);
|
||||||
@@ -143,7 +141,12 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
|||||||
|
|
||||||
void send() {
|
void send() {
|
||||||
sendListener.commitTransaction();
|
sendListener.commitTransaction();
|
||||||
pbProgressSend.setVisibility(View.VISIBLE);
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
pbProgressSend.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -192,12 +195,6 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
|||||||
|
|
||||||
final TxData txData = sendListener.getTxData();
|
final TxData txData = sendListener.getTxData();
|
||||||
tvTxAddress.setText(txData.getDestinationAddress());
|
tvTxAddress.setText(txData.getDestinationAddress());
|
||||||
String paymentId = txData.getPaymentId();
|
|
||||||
if ((paymentId != null) && (!paymentId.isEmpty())) {
|
|
||||||
tvTxPaymentId.setText(txData.getPaymentId());
|
|
||||||
} else {
|
|
||||||
tvTxPaymentId.setText("-");
|
|
||||||
}
|
|
||||||
UserNotes notes = sendListener.getTxData().getUserNotes();
|
UserNotes notes = sendListener.getTxData().getUserNotes();
|
||||||
if ((notes != null) && (!notes.note.isEmpty())) {
|
if ((notes != null) && (!notes.note.isEmpty())) {
|
||||||
tvTxNotes.setText(notes.note);
|
tvTxNotes.setText(notes.note);
|
||||||
@@ -233,103 +230,16 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void preSend() {
|
public void preSend() {
|
||||||
final Activity activity = getActivity();
|
Helper.promptPassword(getContext(), getActivityCallback().getWalletName(), false, new Helper.PasswordAction() {
|
||||||
View promptsView = getLayoutInflater().inflate(R.layout.prompt_password, null);
|
|
||||||
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
|
|
||||||
alertDialogBuilder.setView(promptsView);
|
|
||||||
|
|
||||||
final TextInputLayout etPassword = promptsView.findViewById(R.id.etPassword);
|
|
||||||
etPassword.setHint(getString(R.string.prompt_send_password));
|
|
||||||
|
|
||||||
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void act(String walletName, String password, boolean fingerprintUsed) {
|
||||||
if (etPassword.getError() != null) {
|
send();
|
||||||
etPassword.setError(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
||||||
public void beforeTextChanged(CharSequence s, int start,
|
bSend.setEnabled(true); // allow to try again
|
||||||
int count, int after) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start,
|
|
||||||
int before, int count) {
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
alertDialogBuilder
|
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
|
||||||
if (getActivityCallback().verifyWalletPassword(pass)) {
|
|
||||||
dialog.dismiss();
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
etPassword.setError(getString(R.string.bad_password));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(getString(R.string.label_cancel),
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
dialog.cancel();
|
|
||||||
bSend.setEnabled(true); // allow to try again
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final android.app.AlertDialog passwordDialog = alertDialogBuilder.create();
|
|
||||||
passwordDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
|
||||||
@Override
|
|
||||||
public void onShow(DialogInterface dialog) {
|
|
||||||
Button button = ((android.app.AlertDialog) dialog).getButton(android.app.AlertDialog.BUTTON_POSITIVE);
|
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
|
||||||
if (getActivityCallback().verifyWalletPassword(pass)) {
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
passwordDialog.dismiss();
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
etPassword.setError(getString(R.string.bad_password));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Helper.showKeyboard(passwordDialog);
|
|
||||||
|
|
||||||
// accept keyboard "ok"
|
|
||||||
etPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
|
||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
|
||||||
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
|
||||||
if (getActivityCallback().verifyWalletPassword(pass)) {
|
|
||||||
Helper.hideKeyboardAlways(activity);
|
|
||||||
passwordDialog.dismiss();
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
etPassword.setError(getString(R.string.bad_password));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
|
||||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
|
||||||
passwordDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordDialog.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a pending transaction and calls us back with transactionCreated()
|
// creates a pending transaction and calls us back with transactionCreated()
|
||||||
|
@@ -75,7 +75,7 @@ public class SendFragment extends Fragment
|
|||||||
|
|
||||||
void onPrepareSend(String tag, TxData data);
|
void onPrepareSend(String tag, TxData data);
|
||||||
|
|
||||||
boolean verifyWalletPassword(String password);
|
String getWalletName();
|
||||||
|
|
||||||
void onSend(UserNotes notes);
|
void onSend(UserNotes notes);
|
||||||
|
|
||||||
|
@@ -111,12 +111,6 @@ public class SendSuccessWizardFragment extends SendWizardFragment {
|
|||||||
|
|
||||||
final TxData txData = sendListener.getTxData();
|
final TxData txData = sendListener.getTxData();
|
||||||
tvTxAddress.setText(txData.getDestinationAddress());
|
tvTxAddress.setText(txData.getDestinationAddress());
|
||||||
String paymentId = txData.getPaymentId();
|
|
||||||
if ((paymentId != null) && (!paymentId.isEmpty())) {
|
|
||||||
tvTxPaymentId.setText(txData.getPaymentId());
|
|
||||||
} else {
|
|
||||||
tvTxPaymentId.setText("-");
|
|
||||||
}
|
|
||||||
|
|
||||||
final PendingTx committedTx = sendListener.getCommittedTx();
|
final PendingTx committedTx = sendListener.getCommittedTx();
|
||||||
if (committedTx != null) {
|
if (committedTx != null) {
|
||||||
|
@@ -130,9 +130,9 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
|
|
||||||
private void showStar() {
|
private void showStar() {
|
||||||
if (nodeItem.isFavourite()) {
|
if (nodeItem.isFavourite()) {
|
||||||
ibBookmark.setImageResource(R.drawable.ic_bookmark_24dp);
|
ibBookmark.setImageResource(R.drawable.ic_favorite_24dp);
|
||||||
} else {
|
} else {
|
||||||
ibBookmark.setImageResource(R.drawable.ic_bookmark_border_24dp);
|
ibBookmark.setImageResource(R.drawable.ic_favorite_border_24dp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,12 +17,15 @@
|
|||||||
package com.m2049r.xmrwallet.ledger;
|
package com.m2049r.xmrwallet.ledger;
|
||||||
|
|
||||||
public enum Instruction {
|
public enum Instruction {
|
||||||
|
|
||||||
INS_NONE(0x00),
|
INS_NONE(0x00),
|
||||||
INS_RESET(0x02),
|
INS_RESET(0x02),
|
||||||
INS_GET_KEY(0x20),
|
INS_GET_KEY(0x20),
|
||||||
|
INS_DISPLAY_ADDRESS(0x21),
|
||||||
INS_PUT_KEY(0x22),
|
INS_PUT_KEY(0x22),
|
||||||
INS_GET_CHACHA8_PREKEY(0x24),
|
INS_GET_CHACHA8_PREKEY(0x24),
|
||||||
INS_VERIFY_KEY(0x26),
|
INS_VERIFY_KEY(0x26),
|
||||||
|
INS_MANAGE_SEEDWORDS(0x28),
|
||||||
|
|
||||||
INS_SECRET_KEY_TO_PUBLIC_KEY(0x30),
|
INS_SECRET_KEY_TO_PUBLIC_KEY(0x30),
|
||||||
INS_GEN_KEY_DERIVATION(0x32),
|
INS_GEN_KEY_DERIVATION(0x32),
|
||||||
@@ -30,6 +33,7 @@ public enum Instruction {
|
|||||||
INS_DERIVE_PUBLIC_KEY(0x36),
|
INS_DERIVE_PUBLIC_KEY(0x36),
|
||||||
INS_DERIVE_SECRET_KEY(0x38),
|
INS_DERIVE_SECRET_KEY(0x38),
|
||||||
INS_GEN_KEY_IMAGE(0x3A),
|
INS_GEN_KEY_IMAGE(0x3A),
|
||||||
|
|
||||||
INS_SECRET_KEY_ADD(0x3C),
|
INS_SECRET_KEY_ADD(0x3C),
|
||||||
INS_SECRET_KEY_SUB(0x3E),
|
INS_SECRET_KEY_SUB(0x3E),
|
||||||
INS_GENERATE_KEYPAIR(0x40),
|
INS_GENERATE_KEYPAIR(0x40),
|
||||||
@@ -45,15 +49,20 @@ public enum Instruction {
|
|||||||
INS_SET_SIGNATURE_MODE(0x72),
|
INS_SET_SIGNATURE_MODE(0x72),
|
||||||
INS_GET_ADDITIONAL_KEY(0x74),
|
INS_GET_ADDITIONAL_KEY(0x74),
|
||||||
INS_STEALTH(0x76),
|
INS_STEALTH(0x76),
|
||||||
|
INS_GEN_COMMITMENT_MASK(0x77),
|
||||||
INS_BLIND(0x78),
|
INS_BLIND(0x78),
|
||||||
INS_UNBLIND(0x7A),
|
INS_UNBLIND(0x7A),
|
||||||
|
INS_GEN_TXOUT_KEYS(0x7B),
|
||||||
INS_VALIDATE(0x7C),
|
INS_VALIDATE(0x7C),
|
||||||
|
INS_PREFIX_HASH(0x7D),
|
||||||
INS_MLSAG(0x7E),
|
INS_MLSAG(0x7E),
|
||||||
INS_CLOSE_TX(0x80),
|
INS_CLOSE_TX(0x80),
|
||||||
|
|
||||||
INS_GET_RESPONSE(0xc0),
|
INS_GET_TX_PROOF(0xA0),
|
||||||
|
|
||||||
INS_UNDEFINED(0xff);
|
INS_GET_RESPONSE(0xC0),
|
||||||
|
|
||||||
|
INS_UNDEFINED(0xFF);
|
||||||
|
|
||||||
public static Instruction fromByte(byte n) {
|
public static Instruction fromByte(byte n) {
|
||||||
switch (n & 0xFF) {
|
switch (n & 0xFF) {
|
||||||
@@ -134,6 +143,10 @@ public enum Instruction {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getByteValue() {
|
||||||
|
return (byte) (value & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
private int value;
|
private int value;
|
||||||
|
|
||||||
Instruction(int value) {
|
Instruction(int value) {
|
||||||
|
@@ -27,9 +27,11 @@ import com.btchip.BTChipException;
|
|||||||
import com.btchip.comm.BTChipTransport;
|
import com.btchip.comm.BTChipTransport;
|
||||||
import com.btchip.comm.android.BTChipTransportAndroidHID;
|
import com.btchip.comm.android.BTChipTransportAndroidHID;
|
||||||
import com.m2049r.xmrwallet.BuildConfig;
|
import com.m2049r.xmrwallet.BuildConfig;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -40,9 +42,11 @@ public class Ledger {
|
|||||||
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
||||||
static public final String SUBADDRESS_LOOKAHEAD = LOOKAHEAD_ACCOUNTS + ":" + LOOKAHEAD_SUBADDRESSES;
|
static public final String SUBADDRESS_LOOKAHEAD = LOOKAHEAD_ACCOUNTS + ":" + LOOKAHEAD_SUBADDRESSES;
|
||||||
|
|
||||||
|
private static final byte PROTOCOL_VERSION = 0x03;
|
||||||
public static final int SW_OK = 0x9000;
|
public static final int SW_OK = 0x9000;
|
||||||
public static final int SW_INS_NOT_SUPPORTED = 0x6D00;
|
public static final int SW_INS_NOT_SUPPORTED = 0x6D00;
|
||||||
public static final int OK[] = {SW_OK};
|
public static final int OK[] = {SW_OK};
|
||||||
|
public static final int MINIMUM_LEDGER_VERSION = (1 << 16) + (6 << 8) + (0); // 1.6.0
|
||||||
|
|
||||||
public static UsbDevice findDevice(UsbManager usbManager) {
|
public static UsbDevice findDevice(UsbManager usbManager) {
|
||||||
if (!ENABLED) return null;
|
if (!ENABLED) return null;
|
||||||
@@ -89,6 +93,21 @@ public class Ledger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public boolean check() {
|
||||||
|
if (Instance == null) return false;
|
||||||
|
byte[] moneroVersion = WalletManager.moneroVersion().getBytes(StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] resp = Instance.exchangeApduNoOpt(Instruction.INS_RESET, moneroVersion, OK);
|
||||||
|
int deviceVersion = (resp[0] << 16) + (resp[1] << 8) + (resp[2]);
|
||||||
|
if (deviceVersion < MINIMUM_LEDGER_VERSION)
|
||||||
|
return false;
|
||||||
|
} catch (BTChipException ex) { // comm error - probably wrong app started on device
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
final private BTChipTransport transport;
|
final private BTChipTransport transport;
|
||||||
final private String name;
|
final private String name;
|
||||||
private int lastSW = 0;
|
private int lastSW = 0;
|
||||||
@@ -112,7 +131,7 @@ public class Ledger {
|
|||||||
synchronized private byte[] exchangeRaw(byte[] apdu) {
|
synchronized private byte[] exchangeRaw(byte[] apdu) {
|
||||||
if (transport == null)
|
if (transport == null)
|
||||||
throw new IllegalStateException("No transport (probably closed previously)");
|
throw new IllegalStateException("No transport (probably closed previously)");
|
||||||
Timber.i("exchangeRaw %02x", apdu[1]);
|
Timber.d("exchangeRaw %02x", apdu[1]);
|
||||||
Instruction ins = Instruction.fromByte(apdu[1]);
|
Instruction ins = Instruction.fromByte(apdu[1]);
|
||||||
if (listener != null) listener.onInstructionSend(ins, apdu);
|
if (listener != null) listener.onInstructionSend(ins, apdu);
|
||||||
sniffOut(ins, apdu);
|
sniffOut(ins, apdu);
|
||||||
@@ -120,7 +139,6 @@ public class Ledger {
|
|||||||
if (listener != null) listener.onInstructionReceive(ins, data);
|
if (listener != null) listener.onInstructionReceive(ins, data);
|
||||||
sniffIn(data);
|
sniffIn(data);
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] exchange(byte[] apdu) throws BTChipException {
|
private byte[] exchange(byte[] apdu) throws BTChipException {
|
||||||
@@ -148,68 +166,19 @@ public class Ledger {
|
|||||||
throw new BTChipException("Invalid status", lastSW);
|
throw new BTChipException("Invalid status", lastSW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] exchangeApdu(byte cla, byte ins, byte p1, byte p2, byte[] data, int acceptedSW[]) throws BTChipException {
|
private byte[] exchangeApduNoOpt(Instruction instruction, byte[] data, int acceptedSW[])
|
||||||
byte[] apdu = new byte[data.length + 5];
|
throws BTChipException {
|
||||||
apdu[0] = cla;
|
byte[] apdu = new byte[data.length + 6];
|
||||||
apdu[1] = ins;
|
apdu[0] = PROTOCOL_VERSION;
|
||||||
apdu[2] = p1;
|
apdu[1] = instruction.getByteValue();
|
||||||
apdu[3] = p2;
|
apdu[2] = 0; // p1
|
||||||
apdu[4] = (byte) (data.length);
|
apdu[3] = 0; // p2
|
||||||
System.arraycopy(data, 0, apdu, 5, data.length);
|
apdu[4] = (byte) (data.length + 1); // +1 because the opt byte is part of the data
|
||||||
|
apdu[5] = 0; // opt
|
||||||
|
System.arraycopy(data, 0, apdu, 6, data.length);
|
||||||
return exchangeCheck(apdu, acceptedSW);
|
return exchangeCheck(apdu, acceptedSW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] exchangeApdu(byte cla, byte ins, byte p1, byte p2, int length, int acceptedSW[]) throws BTChipException {
|
|
||||||
byte[] apdu = new byte[5];
|
|
||||||
apdu[0] = cla;
|
|
||||||
apdu[1] = ins;
|
|
||||||
apdu[2] = p1;
|
|
||||||
apdu[3] = p2;
|
|
||||||
apdu[4] = (byte) (length);
|
|
||||||
return exchangeCheck(apdu, acceptedSW);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] exchangeApduSplit(byte cla, byte ins, byte p1, byte p2, byte[] data, int acceptedSW[]) throws BTChipException {
|
|
||||||
int offset = 0;
|
|
||||||
byte[] result = null;
|
|
||||||
while (offset < data.length) {
|
|
||||||
int blockLength = ((data.length - offset) > 255 ? 255 : data.length - offset);
|
|
||||||
byte[] apdu = new byte[blockLength + 5];
|
|
||||||
apdu[0] = cla;
|
|
||||||
apdu[1] = ins;
|
|
||||||
apdu[2] = p1;
|
|
||||||
apdu[3] = p2;
|
|
||||||
apdu[4] = (byte) (blockLength);
|
|
||||||
System.arraycopy(data, offset, apdu, 5, blockLength);
|
|
||||||
result = exchangeCheck(apdu, acceptedSW);
|
|
||||||
offset += blockLength;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] exchangeApduSplit2(byte cla, byte ins, byte p1, byte p2, byte[] data, byte[] data2, int acceptedSW[]) throws BTChipException {
|
|
||||||
int offset = 0;
|
|
||||||
byte[] result = null;
|
|
||||||
int maxBlockSize = 255 - data2.length;
|
|
||||||
while (offset < data.length) {
|
|
||||||
int blockLength = ((data.length - offset) > maxBlockSize ? maxBlockSize : data.length - offset);
|
|
||||||
boolean lastBlock = ((offset + blockLength) == data.length);
|
|
||||||
byte[] apdu = new byte[blockLength + 5 + (lastBlock ? data2.length : 0)];
|
|
||||||
apdu[0] = cla;
|
|
||||||
apdu[1] = ins;
|
|
||||||
apdu[2] = p1;
|
|
||||||
apdu[3] = p2;
|
|
||||||
apdu[4] = (byte) (blockLength + (lastBlock ? data2.length : 0));
|
|
||||||
System.arraycopy(data, offset, apdu, 5, blockLength);
|
|
||||||
if (lastBlock) {
|
|
||||||
System.arraycopy(data2, 0, apdu, 5 + blockLength, data2.length);
|
|
||||||
}
|
|
||||||
result = exchangeCheck(apdu, acceptedSW);
|
|
||||||
offset += blockLength;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void onInstructionSend(Instruction ins, byte[] apdu);
|
void onInstructionSend(Instruction ins, byte[] apdu);
|
||||||
|
|
||||||
@@ -251,7 +220,6 @@ public class Ledger {
|
|||||||
if (ins == Instruction.INS_GET_KEY) {
|
if (ins == Instruction.INS_GET_KEY) {
|
||||||
snoopKey = (apdu[2] == 2);
|
snoopKey = (apdu[2] == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sniffIn(byte[] data) {
|
private void sniffIn(byte[] data) {
|
||||||
|
@@ -51,6 +51,7 @@ public class LedgerProgressDialog extends ProgressDialog implements Ledger.Liste
|
|||||||
switch (ins) {
|
switch (ins) {
|
||||||
case INS_RESET: // ledger may ask for confirmation - maybe a bug?
|
case INS_RESET: // ledger may ask for confirmation - maybe a bug?
|
||||||
case INS_GET_KEY: // ledger asks for confirmation to send keys
|
case INS_GET_KEY: // ledger asks for confirmation to send keys
|
||||||
|
case INS_DISPLAY_ADDRESS:
|
||||||
setIndeterminate(true);
|
setIndeterminate(true);
|
||||||
setMessage(getContext().getString(R.string.progress_ledger_confirm));
|
setMessage(getContext().getString(R.string.progress_ledger_confirm));
|
||||||
break;
|
break;
|
||||||
@@ -102,6 +103,11 @@ public class LedgerProgressDialog extends ProgressDialog implements Ledger.Liste
|
|||||||
setMessage(getContext().getString(R.string.progress_ledger_mlsag));
|
setMessage(getContext().getString(R.string.progress_ledger_mlsag));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case INS_PREFIX_HASH:
|
||||||
|
if ((apdu[2] != 1) || (apdu[3] != 0)) break;
|
||||||
|
setIndeterminate(true);
|
||||||
|
setMessage(getContext().getString(R.string.progress_ledger_confirm));
|
||||||
|
break;
|
||||||
case INS_VALIDATE:
|
case INS_VALIDATE:
|
||||||
if ((apdu[2] != 1) || (apdu[3] != 1)) break;
|
if ((apdu[2] != 1) || (apdu[3] != 1)) break;
|
||||||
validate = true;
|
validate = true;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user