1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-04 17:28:42 +02:00

Compare commits

...

89 Commits

Author SHA1 Message Date
m2049r
46add5e927 bump version v1.14.5 2020-09-21 14:37:51 +02:00
m2049r
fa0692ceab force agree for fingerprint send (#682) 2020-09-21 14:36:17 +02:00
m2049r
ff4f4a1c2c remove notices covered by onboarding (#681) 2020-09-21 14:35:50 +02:00
m2049r
79abb89725 disable button on finish onbaording (#680) 2020-09-21 14:35:25 +02:00
m2049r
ef8301fd6f bump version v1.14.4 2020-09-18 22:09:32 +02:00
hiddener
3a15c842ff updated Romanian translation 2020-09-18 22:01:41 +02:00
m2049r
1697da55b5 only update if we still have a wallet 2020-09-18 22:00:14 +02:00
m2049r
454f3e412a don't do stuff if the wallet is already closed 2020-09-18 22:00:14 +02:00
m2049r
d803a1e220 remove unused resources (#678) 2020-09-18 21:59:38 +02:00
m2049r
f2fe781cb5 update restore heights 2020-09-17 10:18:58 +02:00
m2049r
dcf60ae193 bump version v1.14.3 2020-09-17 09:35:28 +02:00
m2049r
ffdf54c2e1 Merge pull request #677 from m2049r/fix_various
Various fixes & tweaks
2020-09-17 09:34:04 +02:00
m2049r
c060a2ab88 don't show onboarding every time 2020-09-16 19:59:58 +02:00
m2049r
05fc654f3a clean up code 2020-09-16 18:56:27 +02:00
m2049r
c32d157150 monero addresses are 95 characters 2020-09-16 17:51:47 +02:00
m2049r
74e9278baa MainActivity must be singleTop 2020-09-16 17:45:07 +02:00
m2049r
e41e344d63 bump version v1.14.2 2020-09-14 18:16:35 +02:00
m2049r
e66875437d always show onboarding 2020-09-14 18:14:38 +02:00
m2049r
c1d2db3d7d onboarding tweaks & version bump (#676) 2020-09-14 00:24:57 +02:00
m2049r
0c9a2f5e01 fixups 2020-09-13 18:52:26 +02:00
m2049r
64616e3921 onboarding (#675)
Co-authored-by: Stephan <stephan.hagios@gmail.com>
2020-09-13 18:34:22 +02:00
m2049r
82b4d66987 allow spend with fingerprint only (#674) 2020-09-13 18:26:36 +02:00
m2049r
10f2bc6561 upgrade monero core (#673) 2020-09-05 11:01:34 +02:00
m2049r
2ed9a78d9e upgrade gradle 2020-07-16 14:14:26 +02:00
m2049r
ca19f32f8f bump version 2020-07-06 15:00:10 +02:00
m2049r
4431d74051 Fix for Ledger protocol v3 (#670)
* update protocol to V3 for Monero App v1.6.0
2020-07-06 14:59:38 +02:00
TheFuzzStone
f00da6ecda Renamed folder to '*-uk' and files to *-uk. (#666)
* Renamed folder to '*-uk' and files to `*-uk`. 
Changed '&apos;' to '\''

* Renamed file names
2020-06-20 18:07:43 +02:00
m2049r
1cecd0b718 xmr.to v3 API (#667) 2020-06-19 19:17:38 +02:00
m2049r
a0d6117bbb don't keepTimestampsInApk 2020-06-06 09:46:28 +02:00
m2049r
0b0648a172 upgrade dev env 2020-06-05 08:56:02 +02:00
m2049r
775dcf01ae bump version 2020-06-01 20:14:03 +02:00
m2049r
aed4051d44 Merge branch 'TheFuzzStone-master' 2020-06-01 20:09:51 +02:00
m2049r
a586c0781a renamed directory to match locale 2020-06-01 20:08:22 +02:00
m2049r
616d93cb18 replace &apos; 2020-06-01 20:04:55 +02:00
v1docq47
73d9cb6d58 Update for Russian translation (#649)
Update:
 - strings.xml

Co-authored-by: m2049r <m2049r@monerujo.io>
2020-06-01 19:57:33 +02:00
m2049r
9846e8b5cf fix progress bar (#665) 2020-06-01 19:56:24 +02:00
m2049r
aa66a12dac Merge branch 'master' into master 2020-06-01 13:43:16 +02:00
m2049r
65ce9b0889 Update blockheight (#664)
* update through june
2020-06-01 10:04:09 +02:00
m2049r
291e311b8a Enable rescan on wallet (from menu) (#663)
* rescan
2020-06-01 10:03:36 +02:00
m2049r
41290f51fd Upgrade to monero v0.16.0.0 (#662)
* upgrade to monero core v0.16.0.0

* hearts for node favs
2020-06-01 10:02:22 +02:00
m2049r
a11c898e2c bump version 2020-03-09 07:17:46 +01:00
m2049r
9c921183ab catch NPE (#655) 2020-03-08 22:29:02 +01:00
m2049r
b978396a38 fix versionCode 2020-03-08 20:46:23 +01:00
m2049r
c6aa04e986 update heights & fix date parsing bug (#654) 2020-03-08 20:33:34 +01:00
m2049r
6c17b8bd87 update gradle 2020-02-29 10:43:13 +01:00
TheFuzzStone
835a35c6a8 Updating Ukranian language 2020-02-13 13:49:52 +02:00
m2049r
cac32f660c v1.12.11 (monero v0.15.0.1) 2019-11-25 23:30:28 +01:00
m2049r
8e70004bf2 v1.12.10 2019-11-24 17:17:54 +01:00
m2049r
c3a466c392 remove payment id everywhere (#646) 2019-11-24 17:17:25 +01:00
m2049r
e076c19e3e v1.12.9 2019-11-21 10:42:45 +01:00
m2049r
35b717756d Fix amount bugs (#645)
* fix rounding error on send

* fix check funds bug
2019-11-21 10:42:16 +01:00
m2049r
c14486306e v1.12.8 2019-11-20 07:34:25 +01:00
m2049r
c2ef25c377 change error message to 16 for payment ids (#643) 2019-11-20 07:33:29 +01:00
m2049r
b7164ef200 fix XMR missing in open wallet (#642) 2019-11-20 07:33:07 +01:00
m2049r
f94a366d51 v1.12.7 2019-11-19 22:57:43 +01:00
m2049r
286a04b5ef add XMR to receive spinners (again) (#640) 2019-11-19 22:56:28 +01:00
m2049r
1209295a8c v1.12.6 2019-11-18 12:01:49 +01:00
m2049r
037b019d4d xmrto payment through subaddress (#639)
* use subaddress for xmrto only

* fix exchange rate
2019-11-18 12:00:39 +01:00
m2049r
7a1d788f2a UI tweaks (#638)
* fix amount entry field

* password entry on own line

* remove errors when typing; field spacing
2019-11-17 10:31:19 +01:00
m2049r
87d9a8cd95 use kraken for EURXMR exchange rate (#637)
combine with ECB rates for other fiat conversions
2019-11-17 00:42:57 +01:00
m2049r
f637d7f617 update block heights (#636) 2019-11-10 23:54:40 +01:00
m2049r
a4b9a7c6fb fix spend amount & new version (#635) 2019-11-10 15:23:33 +01:00
m2049r
9f01155cb7 v1.12.1 2019-11-10 12:14:52 +01:00
m2049r
08e8a48138 scan only for 0.15 nodes (#634) 2019-11-10 12:13:06 +01:00
m2049r
551c3b9fb6 scan only for 0.15 nodes (#633) 2019-11-10 12:11:01 +01:00
m2049r
2258cb7096 v1.12.0 (#632) 2019-11-10 11:08:19 +01:00
m2049r
6d61841cf3 textfields are filled (#631) 2019-11-10 11:06:34 +01:00
m2049r
c65508d288 upgrade to monero v0.15 (#630) 2019-11-09 22:45:54 +01:00
m2049r
2c3f582672 paste bip70 (#621) 2019-09-22 10:09:18 +02:00
m2049r
f46ba75771 update gradle version (#614) 2019-08-16 19:07:12 +02:00
m2049r
0ce5f2b6ca create ExchangeEditText & use without numpad (#613) 2019-08-04 13:19:42 +02:00
m2049r
110057c294 bump version to 1.11.13 2019-07-14 13:18:27 +02:00
m2049r
7553d3c5f4 Merge pull request #611 from m2049r/fix_heightfix
reduce restore height some more for new wallets
2019-07-14 12:53:24 +02:00
m2049r
317976b34a decrease restore height on new wallet 2019-07-14 12:52:43 +02:00
m2049r
6ad423567f Merge pull request #610 from m2049r/feature_showheight
show restore height
2019-07-14 12:52:21 +02:00
m2049r
d497158856 show restore height 2019-07-14 12:35:00 +02:00
m2049r
f4cada5fa1 Merge pull request #608 from m2049r/feature_nanox
Support for Nano X
2019-07-13 18:56:23 +02:00
m2049r
352f0ad09c update height for 2019-07-01 (#609) 2019-07-13 18:55:35 +02:00
m2049r
ff1a9c1570 verify monero app is running on nano 2019-07-13 18:44:56 +02:00
m2049r
fa811a39a2 accept Nano X over USB 2019-07-13 13:00:24 +02:00
m2049r
cf5018be33 kick 'Hintergrunddienst' (#607) 2019-06-23 21:26:29 +02:00
m2049r
8ec027f9d4 bump version 2019-06-21 08:47:22 +02:00
m2049r
f28428e677 update june restore height (#606) 2019-06-21 08:45:09 +02:00
m2049r
294084bec5 double size of node bookmark icon (#605) 2019-06-21 08:17:08 +02:00
m2049r
4349907627 setNode blocks => call it async (#604) 2019-06-18 08:49:51 +02:00
m2049r
f7cef24a83 fix NPE (#603) 2019-06-18 08:48:28 +02:00
m2049r
2774f99b15 bump version v1.11.10 2019-06-16 23:39:24 +02:00
m2049r
bc630fc445 Refactor secureflag (#600)
* one place to decide if screenshots enabled

* allow screenshots on alpha or debug
2019-06-16 23:28:52 +02:00
m2049r
895cf16d33 don't setDaemon when null (#601) 2019-06-16 23:28:34 +02:00
142 changed files with 4812 additions and 3342 deletions

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@
/app/prodMainnet /app/prodMainnet
/app/alphaStagenet /app/alphaStagenet
/app/prodStagenet /app/prodStagenet
/app/.cxx

View File

@@ -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

View File

@@ -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'
} }

View File

@@ -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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);
} }

View File

@@ -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);
} }

View File

@@ -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

View File

@@ -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);

View 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();
}
}

View File

@@ -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);
} }

View File

@@ -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);
} }
} }

View File

@@ -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)) {

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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");

View File

@@ -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();
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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();
} }

View File

@@ -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);
} }
} }
} }

View File

@@ -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;

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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()

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);
} }
} }

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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