mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-04 00:53:36 +02:00
Compare commits
120 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b978396a38 | ||
![]() |
c6aa04e986 | ||
![]() |
6c17b8bd87 | ||
![]() |
cac32f660c | ||
![]() |
8e70004bf2 | ||
![]() |
c3a466c392 | ||
![]() |
e076c19e3e | ||
![]() |
35b717756d | ||
![]() |
c14486306e | ||
![]() |
c2ef25c377 | ||
![]() |
b7164ef200 | ||
![]() |
f94a366d51 | ||
![]() |
286a04b5ef | ||
![]() |
1209295a8c | ||
![]() |
037b019d4d | ||
![]() |
7a1d788f2a | ||
![]() |
87d9a8cd95 | ||
![]() |
f637d7f617 | ||
![]() |
a4b9a7c6fb | ||
![]() |
9f01155cb7 | ||
![]() |
08e8a48138 | ||
![]() |
551c3b9fb6 | ||
![]() |
2258cb7096 | ||
![]() |
6d61841cf3 | ||
![]() |
c65508d288 | ||
![]() |
2c3f582672 | ||
![]() |
f46ba75771 | ||
![]() |
0ce5f2b6ca | ||
![]() |
110057c294 | ||
![]() |
7553d3c5f4 | ||
![]() |
317976b34a | ||
![]() |
6ad423567f | ||
![]() |
d497158856 | ||
![]() |
f4cada5fa1 | ||
![]() |
352f0ad09c | ||
![]() |
ff1a9c1570 | ||
![]() |
fa811a39a2 | ||
![]() |
cf5018be33 | ||
![]() |
8ec027f9d4 | ||
![]() |
f28428e677 | ||
![]() |
294084bec5 | ||
![]() |
4349907627 | ||
![]() |
f7cef24a83 | ||
![]() |
2774f99b15 | ||
![]() |
bc630fc445 | ||
![]() |
895cf16d33 | ||
![]() |
7f1796b12e | ||
![]() |
abe5c8afab | ||
![]() |
47f79b5269 | ||
![]() |
c9c07eaa15 | ||
![]() |
a490e3af0c | ||
![]() |
64d5b3bdea | ||
![]() |
bf91eaf22f | ||
![]() |
2c3e73b540 | ||
![]() |
830d9dadb9 | ||
![]() |
331d88ebba | ||
![]() |
7cc2f6fafb | ||
![]() |
9a3ee0eda8 | ||
![]() |
6e898939a3 | ||
![]() |
40ae39d647 | ||
![]() |
ca81e652e5 | ||
![]() |
796048be4e | ||
![]() |
441bf995c8 | ||
![]() |
e8860ab8eb | ||
![]() |
525b38ff53 | ||
![]() |
ba79bf87aa | ||
![]() |
3fe6571e7d | ||
![]() |
364e6a8137 | ||
![]() |
cb69ce99d6 | ||
![]() |
1f976872fc | ||
![]() |
27f266b6f7 | ||
![]() |
168928d54a | ||
![]() |
b3f61072aa | ||
![]() |
ccb64aded0 | ||
![]() |
e98fa089f2 | ||
![]() |
884878b7a7 | ||
![]() |
4e23f0ef3a | ||
![]() |
6ea4e3d998 | ||
![]() |
971c90f35b | ||
![]() |
f0523c403c | ||
![]() |
966ed23b87 | ||
![]() |
95f2ca74a6 | ||
![]() |
81d94478f2 | ||
![]() |
16ff779ebc | ||
![]() |
6b7bb164f4 | ||
![]() |
da1d4ea1bf | ||
![]() |
d5a967f690 | ||
![]() |
de8de02f9f | ||
![]() |
06456e33e4 | ||
![]() |
d97b36aa44 | ||
![]() |
8fa06e5b37 | ||
![]() |
8d95de828b | ||
![]() |
93a7be0452 | ||
![]() |
25c8ec1229 | ||
![]() |
0bf0444dce | ||
![]() |
b74f9c6bd7 | ||
![]() |
f843bb1685 | ||
![]() |
7d9d49c29e | ||
![]() |
4ca9328949 | ||
![]() |
08b5a87f19 | ||
![]() |
445d8acc38 | ||
![]() |
9385ac8c31 | ||
![]() |
4c7ebd8402 | ||
![]() |
67f3c5f948 | ||
![]() |
cd67a7e2bf | ||
![]() |
fa5fe313ea | ||
![]() |
ed4957a3cc | ||
![]() |
3e0eeebd51 | ||
![]() |
0d213a1eb4 | ||
![]() |
39d048fd5e | ||
![]() |
1a5d2d0399 | ||
![]() |
028057a672 | ||
![]() |
909ff8ca5e | ||
![]() |
ffd61e4495 | ||
![]() |
003dee382e | ||
![]() |
be0498c67d | ||
![]() |
06227a4a83 | ||
![]() |
4409087bd0 | ||
![]() |
965e52d8a5 | ||
![]() |
beba0f497b |
@@ -3,11 +3,13 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
working_directory: ~/code
|
working_directory: ~/code
|
||||||
docker:
|
docker:
|
||||||
- image: bitriseio/android-ndk
|
- image: circleci/android:api-28-ndk
|
||||||
environment:
|
environment:
|
||||||
JVM_OPTS: -Xmx3200m
|
JVM_OPTS: -Xmx3200m
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
|
- run: yes | sdkmanager --licenses || exit 0
|
||||||
|
- run: yes | sdkmanager --update || exit 0
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
||||||
- run:
|
- run:
|
||||||
|
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
|||||||
workspace.xml
|
|
||||||
markdown-*
|
|
||||||
misc.xml
|
|
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
|||||||
xmrwallet
|
|
22
.idea/compiler.xml
generated
22
.idea/compiler.xml
generated
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<resourceExtensions />
|
|
||||||
<wildcardResourcePatterns>
|
|
||||||
<entry name="!?*.java" />
|
|
||||||
<entry name="!?*.form" />
|
|
||||||
<entry name="!?*.class" />
|
|
||||||
<entry name="!?*.groovy" />
|
|
||||||
<entry name="!?*.scala" />
|
|
||||||
<entry name="!?*.flex" />
|
|
||||||
<entry name="!?*.kt" />
|
|
||||||
<entry name="!?*.clj" />
|
|
||||||
<entry name="!?*.aj" />
|
|
||||||
</wildcardResourcePatterns>
|
|
||||||
<annotationProcessing>
|
|
||||||
<profile default="true" name="Default" enabled="false">
|
|
||||||
<processorPath useClasspath="true" />
|
|
||||||
</profile>
|
|
||||||
</annotationProcessing>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
3
.idea/copyright/profiles_settings.xml
generated
3
.idea/copyright/profiles_settings.xml
generated
@@ -1,3 +0,0 @@
|
|||||||
<component name="CopyrightManager">
|
|
||||||
<settings default="" />
|
|
||||||
</component>
|
|
19
.idea/gradle.xml
generated
19
.idea/gradle.xml
generated
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="disableWrapperSourceDistributionNotification" value="true" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
9
.idea/modules.xml
generated
9
.idea/modules.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/xmrwallet.iml" filepath="$PROJECT_DIR$/xmrwallet.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
12
.idea/runConfigurations.xml
generated
12
.idea/runConfigurations.xml
generated
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RunConfigurationProducerService">
|
|
||||||
<option name="ignoredProducers">
|
|
||||||
<set>
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@@ -137,7 +137,11 @@ set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
|||||||
|
|
||||||
add_library(device STATIC IMPORTED)
|
add_library(device STATIC IMPORTED)
|
||||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||||
|
|
||||||
|
add_library(device_trezor STATIC IMPORTED)
|
||||||
|
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||||
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a)
|
||||||
|
|
||||||
add_library(multisig STATIC IMPORTED)
|
add_library(multisig STATIC IMPORTED)
|
||||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||||
@@ -147,6 +151,22 @@ add_library(version STATIC IMPORTED)
|
|||||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||||
|
|
||||||
|
add_library(net STATIC IMPORTED)
|
||||||
|
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||||
|
${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
|
||||||
#############
|
#############
|
||||||
@@ -166,6 +186,7 @@ target_link_libraries( monerujo
|
|||||||
mnemonics
|
mnemonics
|
||||||
ringct
|
ringct
|
||||||
ringct_basic
|
ringct_basic
|
||||||
|
net
|
||||||
common
|
common
|
||||||
cncrypto
|
cncrypto
|
||||||
blockchain_db
|
blockchain_db
|
||||||
@@ -176,8 +197,12 @@ target_link_libraries( monerujo
|
|||||||
blocks
|
blocks
|
||||||
checkpoints
|
checkpoints
|
||||||
device
|
device
|
||||||
|
device_trezor
|
||||||
multisig
|
multisig
|
||||||
version
|
version
|
||||||
|
randomx
|
||||||
|
hardforks
|
||||||
|
rpc_base
|
||||||
|
|
||||||
boost_chrono
|
boost_chrono
|
||||||
boost_date_time
|
boost_date_time
|
||||||
|
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 162
|
versionCode 202
|
||||||
versionName "1.10.12 'Node-O-matiC'"
|
versionName "1.12.12 'Caerbannog'"
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
@@ -113,10 +113,16 @@ dependencies {
|
|||||||
implementation 'dnsjava:dnsjava:2.1.8'
|
implementation 'dnsjava:dnsjava:2.1.8'
|
||||||
implementation 'org.jitsi:dnssecjava:1.1.3'
|
implementation 'org.jitsi:dnssecjava:1.1.3'
|
||||||
implementation 'org.slf4j:slf4j-nop:1.7.25'
|
implementation 'org.slf4j:slf4j-nop:1.7.25'
|
||||||
|
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/com.github.aelstad/keccakj
|
||||||
|
implementation 'com.github.aelstad:keccakj:1.1.0'
|
||||||
|
|
||||||
|
|
||||||
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
||||||
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
||||||
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
||||||
testImplementation 'org.json:json:20140107'
|
testImplementation 'org.json:json:20180813'
|
||||||
testImplementation 'net.jodah:concurrentunit:0.4.2'
|
testImplementation 'net.jodah:concurrentunit:0.4.4'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -26,14 +26,14 @@
|
|||||||
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="portrait" />
|
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="portrait">
|
android:screenOrientation="locked">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@@ -42,6 +42,22 @@
|
|||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter android:label="@string/app_name">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="monero" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter android:label="@string/app_name">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="bitcoin" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
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" />
|
||||||
@@ -52,5 +68,15 @@
|
|||||||
android:description="@string/service_description"
|
android:description="@string/service_description"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="Monero Wallet Service" />
|
android:label="Monero Wallet Service" />
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="android.support.v4.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/filepaths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
@@ -43,6 +43,9 @@ Copyright (c) 2014 Dushyanth Maguluru
|
|||||||
<h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3>
|
<h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3>
|
||||||
Copyright (c) 2013 Adam Speakman
|
Copyright (c) 2013 Adam Speakman
|
||||||
|
|
||||||
|
<h3>SwipeableRecyclerView (https://github.com/brnunes/SwipeableRecyclerView)</h3>
|
||||||
|
Copyright (c) 2015 Bruno R. Nunes
|
||||||
|
|
||||||
<h3>Apache License, Version 2.0, January 2004</h3>
|
<h3>Apache License, Version 2.0, January 2004</h3>
|
||||||
http://www.apache.org/licenses/<br/>
|
http://www.apache.org/licenses/<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
@@ -1,88 +0,0 @@
|
|||||||
// Copyright (c) 2017-2018, The Monero Project
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without modification, are
|
|
||||||
// permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
||||||
// conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
||||||
// of conditions and the following disclaimer in the documentation and/or other
|
|
||||||
// materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
||||||
// used to endorse or promote products derived from this software without specific
|
|
||||||
// prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
||||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
||||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if defined(HAVE_MONERUJO)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief LedgerFind - find Ledger Device and return it's name
|
|
||||||
* @param buffer - buffer for name of found device
|
|
||||||
* @param len - length of buffer
|
|
||||||
* @return 0 - success
|
|
||||||
* -1 - no device connected / found
|
|
||||||
* -2 - JVM not found
|
|
||||||
*/
|
|
||||||
int LedgerFind(char *buffer, size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief LedgerExchange - exchange data with Ledger Device
|
|
||||||
* @param command - buffer for data to send
|
|
||||||
* @param cmd_len - length of send to send
|
|
||||||
* @param response - buffer for received data
|
|
||||||
* @param max_resp_len - size of receive buffer
|
|
||||||
*
|
|
||||||
* @return length of received data in response or -1 if error
|
|
||||||
*/
|
|
||||||
int LedgerExchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "device_io.hpp"
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace hw {
|
|
||||||
namespace io {
|
|
||||||
class device_io_monerujo: device_io {
|
|
||||||
public:
|
|
||||||
device_io_monerujo() {};
|
|
||||||
~device_io_monerujo() {};
|
|
||||||
|
|
||||||
void init() {};
|
|
||||||
void release() {};
|
|
||||||
|
|
||||||
void connect(void *params) {};
|
|
||||||
void disconnect() {};
|
|
||||||
bool connected() const {return true;}; // monerujo is always connected before it gets here
|
|
||||||
|
|
||||||
// returns number of bytes read or -1 on error
|
|
||||||
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) {
|
|
||||||
return LedgerExchange(command, cmd_len, response, max_resp_len);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //#if defined(HAVE_MONERUJO)
|
|
@@ -39,6 +39,7 @@ static jclass class_WalletListener;
|
|||||||
static jclass class_TransactionInfo;
|
static jclass class_TransactionInfo;
|
||||||
static jclass class_Transfer;
|
static jclass class_Transfer;
|
||||||
static jclass class_Ledger;
|
static jclass class_Ledger;
|
||||||
|
static jclass class_WalletStatus;
|
||||||
|
|
||||||
std::mutex _listenerMutex;
|
std::mutex _listenerMutex;
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
|||||||
jenv->FindClass("com/m2049r/xmrwallet/model/WalletListener")));
|
jenv->FindClass("com/m2049r/xmrwallet/model/WalletListener")));
|
||||||
class_Ledger = static_cast<jclass>(jenv->NewGlobalRef(
|
class_Ledger = static_cast<jclass>(jenv->NewGlobalRef(
|
||||||
jenv->FindClass("com/m2049r/xmrwallet/ledger/Ledger")));
|
jenv->FindClass("com/m2049r/xmrwallet/ledger/Ledger")));
|
||||||
|
class_WalletStatus = static_cast<jclass>(jenv->NewGlobalRef(
|
||||||
|
jenv->FindClass("com/m2049r/xmrwallet/model/Wallet$Status")));
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -442,12 +445,6 @@ Java_com_m2049r_xmrwallet_model_WalletManager_findWallets(JNIEnv *env, jobject i
|
|||||||
return cpp2java(env, walletPaths);
|
return cpp2java(env, walletPaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_com_m2049r_xmrwallet_model_WalletManager_getErrorString(JNIEnv *env, jobject instance) {
|
|
||||||
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
|
||||||
return env->NewStringUTF(wallet->errorString().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
|
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
@@ -587,10 +584,25 @@ Java_com_m2049r_xmrwallet_model_Wallet_getStatusJ(JNIEnv *env, jobject instance)
|
|||||||
return wallet->status();
|
return wallet->status();
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
jobject newWalletStatusInstance(JNIEnv *env, int status, const std::string &errorString) {
|
||||||
Java_com_m2049r_xmrwallet_model_Wallet_getErrorString(JNIEnv *env, jobject instance) {
|
jmethodID init = env->GetMethodID(class_WalletStatus, "<init>",
|
||||||
|
"(ILjava/lang/String;)V");
|
||||||
|
jstring _errorString = env->NewStringUTF(errorString.c_str());
|
||||||
|
jobject instance = env->NewObject(class_WalletStatus, init, status, _errorString);
|
||||||
|
env->DeleteLocalRef(_errorString);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_com_m2049r_xmrwallet_model_Wallet_statusWithErrorString(JNIEnv *env, jobject instance) {
|
||||||
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
||||||
return env->NewStringUTF(wallet->errorString().c_str());
|
|
||||||
|
int status;
|
||||||
|
std::string errorString;
|
||||||
|
wallet->statusWithErrorString(status, errorString);
|
||||||
|
|
||||||
|
return newWalletStatusInstance(env, status, errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
@@ -1298,7 +1310,6 @@ Java_com_m2049r_xmrwallet_model_PendingTransaction_getFirstTxIdJ(JNIEnv *env, jo
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_PendingTransaction_getTxCount(JNIEnv *env, jobject instance) {
|
Java_com_m2049r_xmrwallet_model_PendingTransaction_getTxCount(JNIEnv *env, jobject instance) {
|
||||||
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);
|
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);
|
||||||
@@ -1384,12 +1395,15 @@ Java_com_m2049r_xmrwallet_model_WalletManager_setLogLevel(JNIEnv *env, jclass cl
|
|||||||
Bitmonero::WalletManagerFactory::setLogLevel(level);
|
Bitmonero::WalletManagerFactory::setLogLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_m2049r_xmrwallet_model_WalletManager_moneroVersion(JNIEnv *env, jclass clazz) {
|
||||||
|
return env->NewStringUTF(MONERO_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ledger Stuff
|
// Ledger Stuff
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "device_io_monerujo.hpp"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief LedgerExchange - exchange data with Ledger Device
|
* @brief LedgerExchange - exchange data with Ledger Device
|
||||||
* @param command - buffer for data to send
|
* @param command - buffer for data to send
|
||||||
@@ -1423,7 +1437,7 @@ int LedgerExchange(
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
jsize len = jenv->GetArrayLength(dataRecv);
|
jsize len = jenv->GetArrayLength(dataRecv);
|
||||||
LOGD("LedgerExchange SCARD_S_SUCCESS %ld/%d", cmd_len, len);
|
LOGD("LedgerExchange SCARD_S_SUCCESS %u/%d", cmd_len, len);
|
||||||
if (len <= max_resp_len) {
|
if (len <= max_resp_len) {
|
||||||
jenv->GetByteArrayRegion(dataRecv, 0, len, (jbyte *) response);
|
jenv->GetByteArrayRegion(dataRecv, 0, len, (jbyte *) response);
|
||||||
jenv->DeleteLocalRef(dataRecv);
|
jenv->DeleteLocalRef(dataRecv);
|
||||||
|
@@ -54,20 +54,22 @@ 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,
|
||||||
HASH_DATA_AREA = 136
|
HASH_DATA_AREA = 136
|
||||||
};
|
};
|
||||||
|
|
||||||
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed);
|
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height);
|
||||||
|
|
||||||
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
||||||
cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/);
|
cn_slow_hash(data, length, hash, 0 /*variant*/, 0 /*prehashed*/, 0 /*height*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void slow_hash_broken(const void *data, char *hash, int variant) {
|
inline void slow_hash_broken(const void *data, char *hash, int variant) {
|
||||||
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/);
|
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/, 0 /*height*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -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;
|
||||||
|
@@ -173,10 +173,10 @@ public class LevinReader {
|
|||||||
|
|
||||||
// this should be in LittleEndianDataInputStream because it has little
|
// this should be in LittleEndianDataInputStream because it has little
|
||||||
// endian logic
|
// endian logic
|
||||||
private long readRest(int firstByte, int bytes) throws IOException {
|
private long readRest(final int firstByte, final int bytes) throws IOException {
|
||||||
long result = firstByte;
|
long result = firstByte;
|
||||||
for (int i = 0; i < bytes; i++) {
|
for (int i = 1; i < bytes + 1; i++) {
|
||||||
result = result + (in.readUnsignedByte() << 8);
|
result = result + (((long) in.readUnsignedByte()) << (8 * i));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -33,6 +34,7 @@ import android.view.Menu;
|
|||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@@ -45,6 +47,7 @@ import com.m2049r.xmrwallet.util.FingerprintHelper;
|
|||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||||
import com.m2049r.xmrwallet.util.RestoreHeight;
|
import com.m2049r.xmrwallet.util.RestoreHeight;
|
||||||
|
import com.m2049r.xmrwallet.util.ledger.Monero;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
import com.nulabinc.zxcvbn.Strength;
|
import com.nulabinc.zxcvbn.Strength;
|
||||||
import com.nulabinc.zxcvbn.Zxcvbn;
|
import com.nulabinc.zxcvbn.Zxcvbn;
|
||||||
@@ -76,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) {
|
||||||
@@ -95,7 +115,6 @@ public class GenerateFragment extends Fragment {
|
|||||||
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
|
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
|
||||||
bGenerate = view.findViewById(R.id.bGenerate);
|
bGenerate = view.findViewById(R.id.bGenerate);
|
||||||
|
|
||||||
etWalletMnemonic.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT);
|
|
||||||
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
@@ -108,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) {
|
||||||
@@ -116,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) {
|
||||||
@@ -124,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) {
|
||||||
@@ -132,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) {
|
||||||
@@ -140,6 +182,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clearErrorOnTextEntry(etWalletSpendKey);
|
||||||
|
|
||||||
Helper.showKeyboard(getActivity());
|
Helper.showKeyboard(getActivity());
|
||||||
|
|
||||||
@@ -241,9 +284,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
etWalletAddress.setVisibility(View.VISIBLE);
|
etWalletAddress.setVisibility(View.VISIBLE);
|
||||||
etWalletAddress.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener()
|
etWalletAddress.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
|
||||||
{
|
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
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_NEXT)) {
|
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
@@ -275,9 +316,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
if (type.equals(TYPE_KEY)) {
|
if (type.equals(TYPE_KEY)) {
|
||||||
etWalletSpendKey.setVisibility(View.VISIBLE);
|
etWalletSpendKey.setVisibility(View.VISIBLE);
|
||||||
etWalletSpendKey.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener()
|
etWalletSpendKey.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
|
||||||
{
|
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
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_NEXT)) {
|
|| (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
@@ -304,9 +343,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
bGenerate.setOnClickListener(new View.OnClickListener()
|
bGenerate.setOnClickListener(new View.OnClickListener() {
|
||||||
|
|
||||||
{
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Helper.hideKeyboard(getActivity());
|
Helper.hideKeyboard(getActivity());
|
||||||
@@ -314,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();
|
||||||
|
|
||||||
@@ -416,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");
|
||||||
@@ -617,4 +639,79 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AlertDialog ledgerDialog = null;
|
||||||
|
|
||||||
|
public void convertLedgerSeed() {
|
||||||
|
if (ledgerDialog != null) return;
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
View promptsView = getLayoutInflater().inflate(R.layout.prompt_ledger_seed, null);
|
||||||
|
android.app.AlertDialog.Builder alertDialogBuilder = new android.app.AlertDialog.Builder(activity);
|
||||||
|
alertDialogBuilder.setView(promptsView);
|
||||||
|
|
||||||
|
final TextInputLayout etSeed = promptsView.findViewById(R.id.etSeed);
|
||||||
|
final TextInputLayout etPassphrase = promptsView.findViewById(R.id.etPassphrase);
|
||||||
|
|
||||||
|
etSeed.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
if (etSeed.getError() != null) {
|
||||||
|
etSeed.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) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
alertDialogBuilder
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(getString(R.string.label_ok), null)
|
||||||
|
.setNegativeButton(getString(R.string.label_cancel),
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
Helper.hideKeyboardAlways(activity);
|
||||||
|
etWalletMnemonic.getEditText().getText().clear();
|
||||||
|
dialog.cancel();
|
||||||
|
ledgerDialog = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ledgerDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
|
ledgerDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||||
|
@Override
|
||||||
|
public void onShow(DialogInterface dialog) {
|
||||||
|
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
|
button.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
String ledgerSeed = etSeed.getEditText().getText().toString();
|
||||||
|
String ledgerPassphrase = etPassphrase.getEditText().getText().toString();
|
||||||
|
String moneroSeed = Monero.convert(ledgerSeed, ledgerPassphrase);
|
||||||
|
if (moneroSeed != null) {
|
||||||
|
etWalletMnemonic.getEditText().setText(moneroSeed);
|
||||||
|
ledgerDialog.dismiss();
|
||||||
|
ledgerDialog = null;
|
||||||
|
} else {
|
||||||
|
etSeed.setError(getString(R.string.bad_ledger_seed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Helper.preventScreenshot()) {
|
||||||
|
ledgerDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ledgerDialog.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ import android.view.Menu;
|
|||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
@@ -54,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 {
|
||||||
@@ -71,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;
|
||||||
@@ -98,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);
|
||||||
@@ -187,11 +192,12 @@ 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;
|
||||||
boolean isWatchOnly;
|
boolean isWatchOnly;
|
||||||
Wallet.Status status;
|
Wallet.Status walletStatus;
|
||||||
|
|
||||||
boolean dialogOpened = false;
|
boolean dialogOpened = false;
|
||||||
|
|
||||||
@@ -223,14 +229,15 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
closeWallet = true;
|
closeWallet = true;
|
||||||
}
|
}
|
||||||
name = wallet.getName();
|
name = wallet.getName();
|
||||||
status = wallet.getStatus();
|
walletStatus = wallet.getStatus();
|
||||||
if (status != Wallet.Status.Status_Ok) {
|
if (!walletStatus.isOk()) {
|
||||||
Timber.e(wallet.getErrorString());
|
Timber.e(walletStatus.getErrorString());
|
||||||
if (closeWallet) wallet.close();
|
if (closeWallet) wallet.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
||||||
@@ -263,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);
|
||||||
@@ -286,10 +294,11 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||||
} else {
|
} else {
|
||||||
// TODO show proper error message and/or end the fragment?
|
// TODO show proper error message and/or end the fragment?
|
||||||
tvWalletAddress.setText(status.toString());
|
tvWalletAddress.setText(walletStatus.toString());
|
||||||
tvWalletMnemonic.setText(status.toString());
|
tvWalletHeight.setText(walletStatus.toString());
|
||||||
tvWalletViewKey.setText(status.toString());
|
tvWalletMnemonic.setText(walletStatus.toString());
|
||||||
tvWalletSpendKey.setText(status.toString());
|
tvWalletViewKey.setText(walletStatus.toString());
|
||||||
|
tvWalletSpendKey.setText(walletStatus.toString());
|
||||||
}
|
}
|
||||||
hideProgress();
|
hideProgress();
|
||||||
}
|
}
|
||||||
@@ -413,12 +422,13 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean ok = false;
|
boolean ok = false;
|
||||||
if (wallet.getStatus() == Wallet.Status.Status_Ok) {
|
Wallet.Status walletStatus = wallet.getStatus();
|
||||||
|
if (walletStatus.isOk()) {
|
||||||
wallet.setPassword(newPassword);
|
wallet.setPassword(newPassword);
|
||||||
wallet.store();
|
wallet.store();
|
||||||
ok = true;
|
ok = true;
|
||||||
} else {
|
} else {
|
||||||
Timber.e(wallet.getErrorString());
|
Timber.e(walletStatus.getErrorString());
|
||||||
}
|
}
|
||||||
if (closeWallet) wallet.close();
|
if (closeWallet) wallet.close();
|
||||||
return ok;
|
return ok;
|
||||||
@@ -620,6 +630,11 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (Helper.preventScreenshot()) {
|
||||||
|
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
return openDialog;
|
return openDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -269,7 +269,11 @@ public class LoginActivity extends BaseActivity
|
|||||||
} else {
|
} else {
|
||||||
Timber.i("Waiting for permissions");
|
Timber.i("Waiting for permissions");
|
||||||
}
|
}
|
||||||
processUsbIntent(getIntent());
|
|
||||||
|
// try intents
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (!processUsbIntent(intent))
|
||||||
|
processUriIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean checkServiceRunning() {
|
boolean checkServiceRunning() {
|
||||||
@@ -716,6 +720,10 @@ public class LoginActivity extends BaseActivity
|
|||||||
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
|
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
|
||||||
intent.putExtra(WalletActivity.REQUEST_FINGERPRINT_USED, fingerprintUsed);
|
intent.putExtra(WalletActivity.REQUEST_FINGERPRINT_USED, fingerprintUsed);
|
||||||
intent.putExtra(WalletActivity.REQUEST_STREETMODE, streetmode);
|
intent.putExtra(WalletActivity.REQUEST_STREETMODE, streetmode);
|
||||||
|
if (uri != null) {
|
||||||
|
intent.putExtra(WalletActivity.REQUEST_URI, uri);
|
||||||
|
uri = null; // use only once
|
||||||
|
}
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,6 +918,16 @@ public class LoginActivity extends BaseActivity
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean checkAndCloseWallet(Wallet aWallet) {
|
||||||
|
Wallet.Status walletStatus = aWallet.getStatus();
|
||||||
|
if (!walletStatus.isOk()) {
|
||||||
|
Timber.e(walletStatus.getErrorString());
|
||||||
|
toast(walletStatus.getErrorString());
|
||||||
|
}
|
||||||
|
aWallet.close();
|
||||||
|
return walletStatus.isOk();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGenerate(final String name, final String password) {
|
public void onGenerate(final String name, final String password) {
|
||||||
createWallet(name, password,
|
createWallet(name, password,
|
||||||
@@ -921,15 +939,13 @@ public class LoginActivity extends BaseActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createWallet(File aFile, String password) {
|
public boolean createWallet(File aFile, String password) {
|
||||||
|
NodeInfo currentNode = getNode();
|
||||||
|
// get it from the connected node if we have one, and go back ca. 4 days
|
||||||
|
final long restoreHeight =
|
||||||
|
(currentNode != null) ? currentNode.getHeight() - 2000 : -1;
|
||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE);
|
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
||||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
return checkAndCloseWallet(newWallet);
|
||||||
if (!success) {
|
|
||||||
Timber.e(newWallet.getErrorString());
|
|
||||||
toast(newWallet.getErrorString());
|
|
||||||
}
|
|
||||||
newWallet.close();
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -948,13 +964,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
public boolean createWallet(File aFile, String password) {
|
public boolean createWallet(File aFile, String password) {
|
||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.recoveryWallet(aFile, password, seed, restoreHeight);
|
.recoveryWallet(aFile, password, seed, restoreHeight);
|
||||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
return checkAndCloseWallet(newWallet);
|
||||||
if (!success) {
|
|
||||||
Timber.e(newWallet.getErrorString());
|
|
||||||
toast(newWallet.getErrorString());
|
|
||||||
}
|
|
||||||
newWallet.close();
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -974,13 +984,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.createWalletFromDevice(aFile, password,
|
.createWalletFromDevice(aFile, password,
|
||||||
restoreHeight, "Ledger");
|
restoreHeight, "Ledger");
|
||||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
return checkAndCloseWallet(newWallet);
|
||||||
if (!success) {
|
|
||||||
Timber.e(newWallet.getErrorString());
|
|
||||||
toast(newWallet.getErrorString());
|
|
||||||
}
|
|
||||||
newWallet.close();
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1001,13 +1005,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
Wallet newWallet = WalletManager.getInstance()
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
.createWalletWithKeys(aFile, password, MNEMONIC_LANGUAGE, restoreHeight,
|
.createWalletWithKeys(aFile, password, MNEMONIC_LANGUAGE, restoreHeight,
|
||||||
address, viewKey, spendKey);
|
address, viewKey, spendKey);
|
||||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
return checkAndCloseWallet(newWallet);
|
||||||
if (!success) {
|
|
||||||
Timber.e(newWallet.getErrorString());
|
|
||||||
toast(newWallet.getErrorString());
|
|
||||||
}
|
|
||||||
newWallet.close();
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1221,6 +1219,12 @@ public class LoginActivity extends BaseActivity
|
|||||||
case R.id.action_language:
|
case R.id.action_language:
|
||||||
onChangeLocale();
|
onChangeLocale();
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.action_ledger_seed:
|
||||||
|
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
|
if (f instanceof GenerateFragment) {
|
||||||
|
((GenerateFragment) f).convertLedgerSeed();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
@@ -1353,30 +1357,44 @@ public class LoginActivity extends BaseActivity
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void connectLedger(UsbManager usbManager, final UsbDevice usbDevice) {
|
private void connectLedger(UsbManager usbManager, final UsbDevice usbDevice) {
|
||||||
try {
|
if (Ledger.ENABLED)
|
||||||
Ledger.connect(usbManager, usbDevice);
|
try {
|
||||||
registerDetachReceiver();
|
Ledger.connect(usbManager, usbDevice);
|
||||||
onLedgerAction();
|
if (!Ledger.check()) {
|
||||||
runOnUiThread(new Runnable() {
|
Ledger.disconnect();
|
||||||
@Override
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
Toast.makeText(LoginActivity.this,
|
public void run() {
|
||||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
Toast.makeText(LoginActivity.this,
|
||||||
Toast.LENGTH_SHORT)
|
getString(R.string.toast_ledger_start_app, usbDevice.getProductName()),
|
||||||
.show();
|
Toast.LENGTH_SHORT)
|
||||||
|
.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
|
public void run() {
|
||||||
public void run() {
|
Toast.makeText(LoginActivity.this,
|
||||||
Toast.makeText(LoginActivity.this,
|
getString(R.string.open_wallet_ledger_missing),
|
||||||
getString(R.string.open_wallet_ledger_missing),
|
Toast.LENGTH_SHORT)
|
||||||
Toast.LENGTH_SHORT)
|
.show();
|
||||||
.show();
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1385,7 +1403,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
processUsbIntent(intent);
|
processUsbIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processUsbIntent(Intent intent) {
|
private boolean processUsbIntent(Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
|
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -1398,6 +1416,21 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String uri = null;
|
||||||
|
|
||||||
|
private void processUriIntent(Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_VIEW.equals(action)) {
|
||||||
|
synchronized (this) {
|
||||||
|
uri = intent.getDataString();
|
||||||
|
Timber.d("URI Intent %s", uri);
|
||||||
|
HelpFragment.display(getSupportFragmentManager(), R.string.help_uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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()) {
|
||||||
return nodesToTest.get(0);
|
activityCallback.setNode(bestNode);
|
||||||
else
|
return bestNode;
|
||||||
|
} 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);
|
||||||
|
@@ -32,6 +32,7 @@ import android.view.Menu;
|
|||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -265,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,6 +508,10 @@ public class NodeFragment extends Fragment
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (Helper.preventScreenshot()) {
|
||||||
|
editDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
etNodePass.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
etNodePass.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
|
@@ -17,19 +17,28 @@
|
|||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.nfc.NfcManager;
|
import android.nfc.NfcManager;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import android.support.v7.widget.ShareActionProvider;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
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;
|
||||||
@@ -56,6 +65,9 @@ import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
|||||||
import com.m2049r.xmrwallet.widget.ExchangeView;
|
import com.m2049r.xmrwallet.widget.ExchangeView;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -69,8 +81,8 @@ public class ReceiveFragment extends Fragment {
|
|||||||
private TextInputLayout etNotes;
|
private TextInputLayout etNotes;
|
||||||
private ExchangeView evAmount;
|
private ExchangeView evAmount;
|
||||||
private TextView tvQrCode;
|
private TextView tvQrCode;
|
||||||
private ImageView qrCode;
|
private ImageView ivQrCode;
|
||||||
private ImageView qrCodeFull;
|
private ImageView ivQrCodeFull;
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
private ImageButton bCopyAddress;
|
private ImageButton bCopyAddress;
|
||||||
private Button bSubaddress;
|
private Button bSubaddress;
|
||||||
@@ -97,9 +109,9 @@ public class ReceiveFragment extends Fragment {
|
|||||||
tvAddress = view.findViewById(R.id.tvAddress);
|
tvAddress = view.findViewById(R.id.tvAddress);
|
||||||
etNotes = view.findViewById(R.id.etNotes);
|
etNotes = view.findViewById(R.id.etNotes);
|
||||||
evAmount = view.findViewById(R.id.evAmount);
|
evAmount = view.findViewById(R.id.evAmount);
|
||||||
qrCode = view.findViewById(R.id.qrCode);
|
ivQrCode = view.findViewById(R.id.qrCode);
|
||||||
tvQrCode = view.findViewById(R.id.tvQrCode);
|
tvQrCode = view.findViewById(R.id.tvQrCode);
|
||||||
qrCodeFull = view.findViewById(R.id.qrCodeFull);
|
ivQrCodeFull = view.findViewById(R.id.qrCodeFull);
|
||||||
etDummy = view.findViewById(R.id.etDummy);
|
etDummy = view.findViewById(R.id.etDummy);
|
||||||
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
||||||
bSubaddress = view.findViewById(R.id.bSubaddress);
|
bSubaddress = view.findViewById(R.id.bSubaddress);
|
||||||
@@ -178,25 +190,25 @@ public class ReceiveFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
qrCode.setOnClickListener(new View.OnClickListener() {
|
ivQrCode.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Helper.hideKeyboard(getActivity());
|
Helper.hideKeyboard(getActivity());
|
||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
if (qrValid) {
|
if (qrValid) {
|
||||||
qrCodeFull.setImageBitmap(((BitmapDrawable) qrCode.getDrawable()).getBitmap());
|
ivQrCodeFull.setImageBitmap(((BitmapDrawable) ivQrCode.getDrawable()).getBitmap());
|
||||||
qrCodeFull.setVisibility(View.VISIBLE);
|
ivQrCodeFull.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
evAmount.doExchange();
|
evAmount.doExchange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
qrCodeFull.setOnClickListener(new View.OnClickListener() {
|
ivQrCodeFull.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
qrCodeFull.setImageBitmap(null);
|
ivQrCodeFull.setImageBitmap(null);
|
||||||
qrCodeFull.setVisibility(View.GONE);
|
ivQrCodeFull.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -228,6 +240,81 @@ public class ReceiveFragment extends Fragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShareActionProvider shareActionProvider;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.receive_menu, menu);
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
|
// Locate MenuItem with ShareActionProvider
|
||||||
|
MenuItem item = menu.findItem(R.id.menu_item_share);
|
||||||
|
|
||||||
|
// Fetch and store ShareActionProvider
|
||||||
|
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
|
||||||
|
|
||||||
|
shareActionProvider.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
|
||||||
|
saveQrCode(); // save it only if we need it
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setShareIntent() {
|
||||||
|
if (shareActionProvider != null) {
|
||||||
|
if (qrValid) {
|
||||||
|
shareActionProvider.setShareIntent(getShareIntent());
|
||||||
|
} else {
|
||||||
|
shareActionProvider.setShareIntent(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveQrCode() {
|
||||||
|
if (!qrValid) throw new IllegalStateException("trying to save null qr code!");
|
||||||
|
|
||||||
|
File cachePath = new File(getActivity().getCacheDir(), "images");
|
||||||
|
if (!cachePath.exists())
|
||||||
|
if (!cachePath.mkdirs()) throw new IllegalStateException("cannot create images folder");
|
||||||
|
File png = new File(cachePath, "QR.png");
|
||||||
|
try {
|
||||||
|
FileOutputStream stream = new FileOutputStream(png);
|
||||||
|
Bitmap qrBitmap = ((BitmapDrawable) ivQrCode.getDrawable()).getBitmap();
|
||||||
|
qrBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
|
stream.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Timber.e(ex);
|
||||||
|
// make sure we don't share an old qr code
|
||||||
|
if (!png.delete()) throw new IllegalStateException("cannot delete old qr code");
|
||||||
|
// if we manage to delete it, the URI points to nothing and the user gets a toast with the error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Intent getShareIntent() {
|
||||||
|
File imagePath = new File(getActivity().getCacheDir(), "images");
|
||||||
|
File png = new File(imagePath, "QR.png");
|
||||||
|
Uri contentUri = FileProvider.getUriForFile(getActivity(),
|
||||||
|
BuildConfig.APPLICATION_ID + ".fileprovider", png);
|
||||||
|
if (contentUri != null) {
|
||||||
|
Intent shareIntent = new Intent();
|
||||||
|
shareIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
|
||||||
|
shareIntent.setDataAndType(contentUri, getActivity().getContentResolver().getType(contentUri));
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_TEXT, bcData.getUriString());
|
||||||
|
return shareIntent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void enableSubaddressButton(boolean enable) {
|
void enableSubaddressButton(boolean enable) {
|
||||||
bSubaddress.setEnabled(enable);
|
bSubaddress.setEnabled(enable);
|
||||||
if (enable) {
|
if (enable) {
|
||||||
@@ -242,23 +329,23 @@ public class ReceiveFragment extends Fragment {
|
|||||||
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean qrValid = true;
|
private boolean qrValid = false;
|
||||||
|
|
||||||
void clearQR() {
|
void clearQR() {
|
||||||
if (qrValid) {
|
if (qrValid) {
|
||||||
qrCode.setImageBitmap(null);
|
ivQrCode.setImageBitmap(null);
|
||||||
qrValid = false;
|
qrValid = false;
|
||||||
|
setShareIntent();
|
||||||
if (isLoaded)
|
if (isLoaded)
|
||||||
tvQrCode.setVisibility(View.VISIBLE);
|
tvQrCode.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setQR(Bitmap qr) {
|
void setQR(Bitmap qr) {
|
||||||
qrCode.setImageBitmap(qr);
|
ivQrCode.setImageBitmap(qr);
|
||||||
qrValid = true;
|
qrValid = true;
|
||||||
|
setShareIntent();
|
||||||
tvQrCode.setVisibility(View.GONE);
|
tvQrCode.setVisibility(View.GONE);
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
etDummy.requestFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -392,7 +479,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, null, notes, xmrAmount);
|
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, null, notes, xmrAmount);
|
||||||
int size = Math.min(qrCode.getHeight(), qrCode.getWidth());
|
int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight());
|
||||||
Bitmap qr = generate(bcData.getUriString(), size, size);
|
Bitmap qr = generate(bcData.getUriString(), size, size);
|
||||||
if (qr != null) {
|
if (qr != null) {
|
||||||
setQR(qr);
|
setQR(qr);
|
||||||
@@ -422,8 +509,8 @@ public class ReceiveFragment extends Fragment {
|
|||||||
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
|
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
|
||||||
bitmap = addLogo(bitmap);
|
bitmap = addLogo(bitmap);
|
||||||
return bitmap;
|
return bitmap;
|
||||||
} catch (WriterException e) {
|
} catch (WriterException ex) {
|
||||||
e.printStackTrace();
|
Timber.e(ex);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -487,6 +574,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
Timber.d("onPause()");
|
Timber.d("onPause()");
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ import com.m2049r.xmrwallet.model.TransactionInfo;
|
|||||||
import com.m2049r.xmrwallet.model.Transfer;
|
import com.m2049r.xmrwallet.model.Transfer;
|
||||||
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.UserNotes;
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -71,7 +71,6 @@ public class TxFragment extends Fragment {
|
|||||||
private TextView tvTxFee;
|
private TextView tvTxFee;
|
||||||
private TextView tvTxTransfers;
|
private TextView tvTxTransfers;
|
||||||
private TextView etTxNotes;
|
private TextView etTxNotes;
|
||||||
private Button bTxNotes;
|
|
||||||
|
|
||||||
// XMRTO stuff
|
// XMRTO stuff
|
||||||
private View cvXmrTo;
|
private View cvXmrTo;
|
||||||
@@ -102,21 +101,9 @@ public class TxFragment extends Fragment {
|
|||||||
tvTxFee = view.findViewById(R.id.tvTxFee);
|
tvTxFee = view.findViewById(R.id.tvTxFee);
|
||||||
tvTxTransfers = view.findViewById(R.id.tvTxTransfers);
|
tvTxTransfers = view.findViewById(R.id.tvTxTransfers);
|
||||||
etTxNotes = view.findViewById(R.id.etTxNotes);
|
etTxNotes = view.findViewById(R.id.etTxNotes);
|
||||||
bTxNotes = view.findViewById(R.id.bTxNotes);
|
|
||||||
|
|
||||||
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
|
||||||
bTxNotes.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
info.notes = null; // force reload on next view
|
|
||||||
bTxNotes.setEnabled(false);
|
|
||||||
etTxNotes.setEnabled(false);
|
|
||||||
userNotes.setNote(etTxNotes.getText().toString());
|
|
||||||
activityCallback.onSetNote(info.hash, userNotes.txNotes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@@ -131,14 +118,6 @@ public class TxFragment extends Fragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onNotesSet(boolean reload) {
|
|
||||||
bTxNotes.setEnabled(true);
|
|
||||||
etTxNotes.setEnabled(true);
|
|
||||||
if (reload) {
|
|
||||||
loadNotes(this.info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shareTxInfo() {
|
void shareTxInfo() {
|
||||||
if (this.info == null) return;
|
if (this.info == null) return;
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
@@ -315,7 +294,6 @@ public class TxFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -337,9 +315,9 @@ public class TxFragment extends Fragment {
|
|||||||
|
|
||||||
String getTxNotes(String hash);
|
String getTxNotes(String hash);
|
||||||
|
|
||||||
String getTxAddress(int major, int minor);
|
boolean setTxNotes(String txId, String txNotes);
|
||||||
|
|
||||||
void onSetNote(String txId, String notes);
|
String getTxAddress(int major, int minor);
|
||||||
|
|
||||||
void setToolbarButton(int type);
|
void setToolbarButton(int type);
|
||||||
|
|
||||||
@@ -357,4 +335,16 @@ public class TxFragment extends Fragment {
|
|||||||
+ " must implement Listener");
|
+ " must implement Listener");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
if (!etTxNotes.getText().toString().equals(userNotes.note)) { // notes have changed
|
||||||
|
// save them
|
||||||
|
userNotes.setNote(etTxNotes.getText().toString());
|
||||||
|
info.notes = userNotes.txNotes;
|
||||||
|
activityCallback.setTxNotes(info.hash, info.notes);
|
||||||
|
}
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
}
|
@@ -47,6 +47,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||||
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
||||||
@@ -59,7 +60,6 @@ import com.m2049r.xmrwallet.model.WalletManager;
|
|||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
import com.m2049r.xmrwallet.util.UserNotes;
|
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -81,6 +81,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
public static final String REQUEST_PW = "pw";
|
public static final String REQUEST_PW = "pw";
|
||||||
public static final String REQUEST_FINGERPRINT_USED = "fingerprint";
|
public static final String REQUEST_FINGERPRINT_USED = "fingerprint";
|
||||||
public static final String REQUEST_STREETMODE = "streetmode";
|
public static final String REQUEST_STREETMODE = "streetmode";
|
||||||
|
public static final String REQUEST_URI = "uri";
|
||||||
|
|
||||||
private NavigationView accountsView;
|
private NavigationView accountsView;
|
||||||
private DrawerLayout drawer;
|
private DrawerLayout drawer;
|
||||||
@@ -92,6 +93,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
private String uri = null;
|
||||||
|
|
||||||
private long streetMode = 0;
|
private long streetMode = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -144,8 +147,16 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
} else {
|
} else {
|
||||||
streetMode = 0;
|
streetMode = 0;
|
||||||
}
|
}
|
||||||
updateAccountsBalance();
|
final WalletFragment walletFragment = (WalletFragment)
|
||||||
|
getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName());
|
||||||
|
if (walletFragment != null) walletFragment.resetDismissedTransactions();
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateAccountsBalance();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -168,6 +179,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
return getWallet().getUserNote(txId);
|
return getWallet().getUserNote(txId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setTxNotes(String txId, String txNotes) {
|
||||||
|
return getWallet().setUserNote(txId, txNotes);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTxAddress(int major, int minor) {
|
public String getTxAddress(int major, int minor) {
|
||||||
return getWallet().getSubaddress(major, minor);
|
return getWallet().getSubaddress(major, minor);
|
||||||
@@ -188,6 +204,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
// 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);
|
||||||
|
uri = extras.getString(REQUEST_URI);
|
||||||
connectWalletService(walletId, password);
|
connectWalletService(walletId, password);
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
@@ -286,7 +303,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
showNet();
|
showNet();
|
||||||
}
|
}
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onEnableStreetMode() {
|
private void onEnableStreetMode() {
|
||||||
@@ -510,7 +526,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendRequest() {
|
public void onSendRequest() {
|
||||||
replaceFragment(new SendFragment(), null, null);
|
replaceFragment(SendFragment.newInstance(uri), null, null);
|
||||||
|
uri = null; // only use uri once
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -611,23 +628,22 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWalletStarted(final Wallet.ConnectionStatus connStatus) {
|
public void onWalletStarted(final Wallet.Status walletStatus) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
dismissProgressDialog();
|
dismissProgressDialog();
|
||||||
switch (connStatus) {
|
if (walletStatus == null) {
|
||||||
case ConnectionStatus_Disconnected:
|
// guess what went wrong
|
||||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show();
|
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show();
|
||||||
break;
|
} else {
|
||||||
case ConnectionStatus_WrongVersion:
|
if (Wallet.ConnectionStatus.ConnectionStatus_WrongVersion == walletStatus.getConnectionStatus())
|
||||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show();
|
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show();
|
||||||
break;
|
else if (!walletStatus.isOk())
|
||||||
case ConnectionStatus_Connected:
|
Toast.makeText(WalletActivity.this, walletStatus.getErrorString(), Toast.LENGTH_LONG).show();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
if ((walletStatus == null) || (Wallet.ConnectionStatus.ConnectionStatus_Connected != walletStatus.getConnectionStatus())) {
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
haveWallet = true;
|
haveWallet = true;
|
||||||
@@ -706,26 +722,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSetNotes(final boolean success) {
|
|
||||||
try {
|
|
||||||
final TxFragment txFragment = (TxFragment)
|
|
||||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (!success) {
|
|
||||||
Toast.makeText(WalletActivity.this, getString(R.string.tx_notes_set_failed), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
txFragment.onNotesSet(success);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (ClassCastException ex) {
|
|
||||||
// not in tx fragment
|
|
||||||
Timber.d(ex.getLocalizedMessage());
|
|
||||||
// never mind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProgress(final String text) {
|
public void onProgress(final String text) {
|
||||||
try {
|
try {
|
||||||
@@ -787,21 +783,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSetNote(String txId, String notes) {
|
|
||||||
if (mIsBound) { // no point in talking to unbound service
|
|
||||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
|
||||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_SETNOTE);
|
|
||||||
intent.putExtra(WalletService.REQUEST_CMD_SETNOTE_TX, txId);
|
|
||||||
intent.putExtra(WalletService.REQUEST_CMD_SETNOTE_NOTES, notes);
|
|
||||||
startService(intent);
|
|
||||||
Timber.d("SET NOTE request sent");
|
|
||||||
} else {
|
|
||||||
Timber.e("Service not bound");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareSend(final String tag, final TxData txData) {
|
public void onPrepareSend(final String tag, final TxData txData) {
|
||||||
if (mIsBound) { // no point in talking to unbound service
|
if (mIsBound) { // no point in talking to unbound service
|
||||||
@@ -956,8 +937,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
if (!processed || (onUriScannedListener == null)) {
|
if (!processed || (onUriScannedListener == null)) {
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_read_what), Toast.LENGTH_LONG).show();
|
Toast.makeText(this, getString(R.string.nfc_tag_read_what), Toast.LENGTH_LONG).show();
|
||||||
} else {
|
|
||||||
Toast.makeText(this, getString(R.string.nfc_tag_read_success), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1057,6 +1036,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
} else {
|
} else {
|
||||||
tvBalance.setText(null);
|
tvBalance.setText(null);
|
||||||
}
|
}
|
||||||
|
updateAccountsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAccountsHeader() {
|
void updateAccountsHeader() {
|
||||||
@@ -1070,8 +1050,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
Menu menu = accountsView.getMenu();
|
Menu menu = accountsView.getMenu();
|
||||||
menu.removeGroup(R.id.accounts_list);
|
menu.removeGroup(R.id.accounts_list);
|
||||||
final int n = wallet.getNumAccounts();
|
final int n = wallet.getNumAccounts();
|
||||||
|
final boolean showBalances = (n > 1) && !isStreetMode();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
final String label = wallet.getAccountLabel(i);
|
final String label = (showBalances ?
|
||||||
|
getString(R.string.label_account, wallet.getAccountLabel(i), Helper.getDisplayAmount(wallet.getBalance(i), 2))
|
||||||
|
: wallet.getAccountLabel(i));
|
||||||
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
|
final MenuItem item = menu.add(R.id.accounts_list, getAccountId(i), 2 * i, label);
|
||||||
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
|
item.setIcon(R.drawable.ic_account_balance_wallet_black_24dp);
|
||||||
if (i == wallet.getAccountIndex())
|
if (i == wallet.getAccountIndex())
|
||||||
|
@@ -38,6 +38,7 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
|
||||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
@@ -49,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;
|
||||||
|
|
||||||
@@ -73,6 +73,12 @@ public class WalletFragment extends Fragment
|
|||||||
|
|
||||||
private Spinner sCurrency;
|
private Spinner sCurrency;
|
||||||
|
|
||||||
|
private List<String> dismissedTransactions = new ArrayList<>();
|
||||||
|
|
||||||
|
public void resetDismissedTransactions() {
|
||||||
|
dismissedTransactions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -107,18 +113,56 @@ 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);
|
||||||
|
|
||||||
RecyclerView recyclerView = view.findViewById(R.id.list);
|
RecyclerView recyclerView = view.findViewById(R.id.list);
|
||||||
|
|
||||||
this.adapter = new TransactionInfoAdapter(getActivity(), this);
|
adapter = new TransactionInfoAdapter(getActivity(), this);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
SwipeableRecyclerViewTouchListener swipeTouchListener =
|
||||||
|
new SwipeableRecyclerViewTouchListener(recyclerView,
|
||||||
|
new SwipeableRecyclerViewTouchListener.SwipeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean canSwipeLeft(int position) {
|
||||||
|
return activityCallback.isStreetMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSwipeRight(int position) {
|
||||||
|
return activityCallback.isStreetMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
|
||||||
|
for (int position : reverseSortedPositions) {
|
||||||
|
dismissedTransactions.add(adapter.getItem(position).hash);
|
||||||
|
adapter.removeItem(position);
|
||||||
|
}
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
|
||||||
|
for (int position : reverseSortedPositions) {
|
||||||
|
dismissedTransactions.add(adapter.getItem(position).hash);
|
||||||
|
adapter.removeItem(position);
|
||||||
|
}
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
recyclerView.addOnItemTouchListener(swipeTouchListener);
|
||||||
|
|
||||||
|
|
||||||
bSend.setOnClickListener(new View.OnClickListener() {
|
bSend.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@@ -177,8 +221,8 @@ public class WalletFragment extends Fragment
|
|||||||
if (isExchanging) return; // wait for exchange to finish - it will fire this itself then.
|
if (isExchanging) return; // wait for exchange to finish - it will fire this itself then.
|
||||||
// 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 = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // crash if this fails!
|
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
|
||||||
@@ -187,23 +231,23 @@ 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();
|
||||||
|
|
||||||
void refreshBalance() {
|
void refreshBalance() {
|
||||||
double unconfirmedXmr = Double.parseDouble(Helper.getDisplayAmount(balance - unlockedBalance));
|
double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue();
|
||||||
showUnconfirmed(unconfirmedXmr);
|
showUnconfirmed(unconfirmedXmr);
|
||||||
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
if (sCurrency.getSelectedItemPosition() == 0) { // XMR
|
||||||
double amountXmr = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
double amountXmr = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||||
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
||||||
} else { // not XMR
|
} else { // not XMR
|
||||||
String currency = (String) sCurrency.getSelectedItem();
|
String currency = (String) sCurrency.getSelectedItem();
|
||||||
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) {
|
||||||
@@ -252,17 +296,17 @@ public class WalletFragment extends Fragment
|
|||||||
|
|
||||||
public void exchangeFailed() {
|
public void exchangeFailed() {
|
||||||
sCurrency.setSelection(0, true); // default to XMR
|
sCurrency.setSelection(0, true); // default to XMR
|
||||||
double amountXmr = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // assume this cannot fail!
|
double amountXmr = Helper.getDecimalAmount(unlockedBalance).doubleValue();
|
||||||
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
showBalance(Helper.getFormattedAmount(amountXmr, true));
|
||||||
hideExchanging();
|
hideExchanging();
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
||||||
@@ -294,7 +338,9 @@ public class WalletFragment extends Fragment
|
|||||||
Timber.d("StreetHeight=%d", streetHeight);
|
Timber.d("StreetHeight=%d", streetHeight);
|
||||||
for (TransactionInfo info : wallet.getHistory().getAll()) {
|
for (TransactionInfo info : wallet.getHistory().getAll()) {
|
||||||
Timber.d("TxHeight=%d", info.blockheight);
|
Timber.d("TxHeight=%d", info.blockheight);
|
||||||
if (info.isPending || (info.blockheight >= streetHeight)) list.add(info);
|
if ((info.isPending || (info.blockheight >= streetHeight))
|
||||||
|
&& !dismissedTransactions.contains(info.hash))
|
||||||
|
list.add(info);
|
||||||
}
|
}
|
||||||
adapter.setInfos(list);
|
adapter.setInfos(list);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
|
@@ -21,7 +21,10 @@ import android.net.Uri;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||||
import com.m2049r.xmrwallet.util.OpenAliasHelper;
|
import com.m2049r.xmrwallet.util.OpenAliasHelper;
|
||||||
|
import com.m2049r.xmrwallet.util.PaymentProtocolHelper;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -37,9 +40,10 @@ public class BarcodeData {
|
|||||||
public static final String OA_XMR_ASSET = "xmr";
|
public static final String OA_XMR_ASSET = "xmr";
|
||||||
public static final String OA_BTC_ASSET = "btc";
|
public static final String OA_BTC_ASSET = "btc";
|
||||||
|
|
||||||
static final String BTC_SCHEME = "bitcoin:";
|
static final String BTC_SCHEME = "bitcoin";
|
||||||
static final String BTC_DESCRIPTION = "message";
|
static final String BTC_DESCRIPTION = "message";
|
||||||
static final String BTC_AMOUNT = "amount";
|
static final String BTC_AMOUNT = "amount";
|
||||||
|
static final String BTC_BIP70_PARM = "r";
|
||||||
|
|
||||||
public enum Asset {
|
public enum Asset {
|
||||||
XMR, BTC
|
XMR, BTC
|
||||||
@@ -48,67 +52,49 @@ public class BarcodeData {
|
|||||||
public enum Security {
|
public enum Security {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
OA_NO_DNSSEC,
|
OA_NO_DNSSEC,
|
||||||
OA_DNSSEC
|
OA_DNSSEC,
|
||||||
|
BIP70
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address) {
|
public BarcodeData(Asset asset, String address) {
|
||||||
this.asset = asset;
|
this(asset, address, null, null, null, Security.NORMAL);
|
||||||
this.address = address;
|
|
||||||
amount = null;
|
|
||||||
paymentId = null;
|
|
||||||
addressName = null;
|
|
||||||
description = null;
|
|
||||||
this.security = Security.NORMAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String amount) {
|
public BarcodeData(Asset asset, String address, String amount) {
|
||||||
this.asset = asset;
|
this(asset, address, null, null, amount, Security.NORMAL);
|
||||||
this.address = address;
|
|
||||||
this.amount = amount;
|
|
||||||
paymentId = null;
|
|
||||||
addressName = null;
|
|
||||||
description = null;
|
|
||||||
this.security = Security.NORMAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
|
public BarcodeData(Asset asset, String address, String amount, String description, Security security) {
|
||||||
this.asset = asset;
|
this(asset, address, null, description, amount, security);
|
||||||
this.address = address;
|
|
||||||
this.paymentId = paymentId;
|
|
||||||
this.amount = amount;
|
|
||||||
addressName = null;
|
|
||||||
description = null;
|
|
||||||
this.security = 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 = asset;
|
this(asset, address, null, description, amount, Security.NORMAL);
|
||||||
this.address = address;
|
|
||||||
this.paymentId = paymentId;
|
|
||||||
this.description = description;
|
|
||||||
this.amount = amount;
|
|
||||||
addressName = null;
|
|
||||||
this.security = Security.NORMAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarcodeData(Asset asset, String address, String addressName, String paymentId, String description, String amount, Security sec) {
|
public BarcodeData(Asset asset, String address, String addressName, String description, String amount, Security security) {
|
||||||
|
this(asset, address, addressName, null, description, amount, 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.addressName = addressName;
|
this.addressName = addressName;
|
||||||
this.paymentId = paymentId;
|
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.security = sec;
|
this.security = security;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Uri getUri() {
|
public Uri getUri() {
|
||||||
return Uri.parse(getUriString());
|
return Uri.parse(getUriString());
|
||||||
}
|
}
|
||||||
@@ -118,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;
|
||||||
@@ -146,6 +127,10 @@ public class BarcodeData {
|
|||||||
if (bcData == null) {
|
if (bcData == null) {
|
||||||
bcData = parseBitcoinUri(qrCode);
|
bcData = parseBitcoinUri(qrCode);
|
||||||
}
|
}
|
||||||
|
// check for btc payment uri (like bitpay)
|
||||||
|
if (bcData == null) {
|
||||||
|
bcData = parseBitcoinPaymentUrl(qrCode);
|
||||||
|
}
|
||||||
// check for naked btc address
|
// check for naked btc address
|
||||||
if (bcData == null) {
|
if (bcData == null) {
|
||||||
bcData = parseBitcoinNaked(qrCode);
|
bcData = parseBitcoinNaked(qrCode);
|
||||||
@@ -189,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);
|
||||||
@@ -202,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");
|
||||||
@@ -228,19 +212,28 @@ public class BarcodeData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01
|
// bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01
|
||||||
static public BarcodeData parseBitcoinUri(String uri) {
|
// bitcoin:?r=https://bitpay.com/i/xxx
|
||||||
Timber.d("parseBitcoinUri=%s", uri);
|
static public BarcodeData parseBitcoinUri(String uriString) {
|
||||||
|
Timber.d("parseBitcoinUri=%s", uriString);
|
||||||
|
|
||||||
if (uri == null) return null;
|
if (uriString == null) return null;
|
||||||
|
URI uri;
|
||||||
|
try {
|
||||||
|
uri = new URI(uriString);
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!uri.isOpaque() ||
|
||||||
|
!uri.getScheme().equals(BTC_SCHEME)) return null;
|
||||||
|
|
||||||
if (!uri.startsWith(BTC_SCHEME)) return null;
|
String[] parts = uri.getRawSchemeSpecificPart().split("[?]");
|
||||||
|
if ((parts.length <= 0) || (parts.length > 2)) {
|
||||||
String noScheme = uri.substring(BTC_SCHEME.length());
|
Timber.d("invalid number of parts %d", parts.length);
|
||||||
Uri bitcoin = Uri.parse(noScheme);
|
return null;
|
||||||
|
}
|
||||||
Map<String, String> parms = new HashMap<>();
|
Map<String, String> parms = new HashMap<>();
|
||||||
String query = bitcoin.getQuery();
|
if (parts.length == 2) {
|
||||||
if (query != null) {
|
String[] args = parts[1].split("&");
|
||||||
String[] args = query.split("&");
|
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
String[] namevalue = arg.split("=");
|
String[] namevalue = arg.split("=");
|
||||||
if (namevalue.length == 0) {
|
if (namevalue.length == 0) {
|
||||||
@@ -250,10 +243,26 @@ public class BarcodeData {
|
|||||||
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
|
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String address = bitcoin.getPath();
|
|
||||||
String description = parms.get(BTC_DESCRIPTION);
|
String description = parms.get(BTC_DESCRIPTION);
|
||||||
|
String address = parts[0]; // no need to decode as there can bo no special characters
|
||||||
|
if (address.isEmpty()) { // possibly a BIP72 uri
|
||||||
|
String bip70 = parms.get(BTC_BIP70_PARM);
|
||||||
|
if (bip70 == null) {
|
||||||
|
Timber.d("no address and can't find pp url");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!PaymentProtocolHelper.isHttp(bip70)) {
|
||||||
|
Timber.d("[%s] is not http url", bip70);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new BarcodeData(BarcodeData.Asset.BTC, null, null, bip70, description, null, Security.NORMAL);
|
||||||
|
}
|
||||||
|
if (!BitcoinAddressValidator.validate(address)) {
|
||||||
|
Timber.d("BTC address (%s) invalid", address);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
String amount = parms.get(BTC_AMOUNT);
|
String amount = parms.get(BTC_AMOUNT);
|
||||||
if (amount != null) {
|
if ((amount != null) && (!amount.isEmpty())) {
|
||||||
try {
|
try {
|
||||||
Double.parseDouble(amount);
|
Double.parseDouble(amount);
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
@@ -261,11 +270,22 @@ 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 (!BitcoinAddressValidator.validate(address)) {
|
return new BarcodeData(BarcodeData.Asset.BTC, address, null, description, amount);
|
||||||
Timber.d("address invalid");
|
}
|
||||||
|
|
||||||
|
// https://bitpay.com/invoice?id=xxx
|
||||||
|
// https://bitpay.com/i/KbMdd4EhnLXSbpWGKsaeo6
|
||||||
|
static public BarcodeData parseBitcoinPaymentUrl(String url) {
|
||||||
|
Timber.d("parseBitcoinUri=%s", url);
|
||||||
|
|
||||||
|
if (url == null) return null;
|
||||||
|
|
||||||
|
if (!PaymentProtocolHelper.isHttp(url)) {
|
||||||
|
Timber.d("[%s] is not http url", url);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new BarcodeData(BarcodeData.Asset.BTC, address, null, description, amount);
|
|
||||||
|
return new BarcodeData(Asset.BTC, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
static public BarcodeData parseBitcoinNaked(String address) {
|
static public BarcodeData parseBitcoinNaked(String address) {
|
||||||
|
@@ -46,7 +46,8 @@ import okhttp3.ResponseBody;
|
|||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class NodeInfo extends Node {
|
public class NodeInfo extends Node {
|
||||||
final static public int MIN_MAJOR_VERSION = 9;
|
final static public int MIN_MAJOR_VERSION = 11;
|
||||||
|
final static public String RPC_VERSION = "2.0";
|
||||||
|
|
||||||
private long height = 0;
|
private long height = 0;
|
||||||
private long timestamp = 0;
|
private long timestamp = 0;
|
||||||
@@ -228,11 +229,16 @@ public class NodeInfo extends Node {
|
|||||||
responseCode = response.code();
|
responseCode = response.code();
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
ResponseBody respBody = response.body(); // closed through Response object
|
ResponseBody respBody = response.body(); // closed through Response object
|
||||||
if ((respBody != null) && (respBody.contentLength() < 1000)) { // sanity check
|
if ((respBody != null) && (respBody.contentLength() < 2000)) { // sanity check
|
||||||
final JSONObject json = new JSONObject(
|
final JSONObject json = new JSONObject(
|
||||||
respBody.string());
|
respBody.string());
|
||||||
final JSONObject header = json.getJSONObject(
|
String rpcVersion = json.getString("jsonrpc");
|
||||||
"result").getJSONObject("block_header");
|
if (!RPC_VERSION.equals(rpcVersion))
|
||||||
|
return false;
|
||||||
|
final JSONObject result = json.getJSONObject("result");
|
||||||
|
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");
|
||||||
|
@@ -20,9 +20,6 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.util.UserNotes;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
|
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
|
||||||
public class TxData implements Parcelable {
|
public class TxData implements Parcelable {
|
||||||
@@ -32,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;
|
||||||
@@ -54,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;
|
||||||
}
|
}
|
||||||
@@ -74,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;
|
||||||
}
|
}
|
||||||
@@ -99,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;
|
||||||
@@ -109,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());
|
||||||
@@ -128,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());
|
||||||
@@ -145,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user