mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-03 08:23:04 +02:00
Compare commits
150 Commits
v1.1.3-alp
...
v1.5.5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8985511209 | ||
![]() |
3c8a4ce967 | ||
![]() |
fcfedbcfae | ||
![]() |
74279b135a | ||
![]() |
d6d2de8312 | ||
![]() |
af0ecb2894 | ||
![]() |
975cc4f43c | ||
![]() |
74ba36de26 | ||
![]() |
7627e15a48 | ||
![]() |
37244cb9e0 | ||
![]() |
843566b820 | ||
![]() |
0bcf156929 | ||
![]() |
b1d91e2671 | ||
![]() |
271cd2d4a8 | ||
![]() |
22c5a543db | ||
![]() |
cd986860c5 | ||
![]() |
0cf5981eae | ||
![]() |
e109df34f0 | ||
![]() |
5a7aa6cc77 | ||
![]() |
f50629ff81 | ||
![]() |
cb12d64e5f | ||
![]() |
a8f08fb9b9 | ||
![]() |
3e9be418a8 | ||
![]() |
fa5dc9988d | ||
![]() |
857cf8d6d8 | ||
![]() |
63e0c265cb | ||
![]() |
39d2c0a25f | ||
![]() |
ff6e00e1a1 | ||
![]() |
3a839a04d5 | ||
![]() |
42e4db5cc1 | ||
![]() |
d18999e731 | ||
![]() |
425246beb1 | ||
![]() |
e1a2572236 | ||
![]() |
7fdae76f51 | ||
![]() |
b4e1767a7b | ||
![]() |
9b9995437d | ||
![]() |
94abc00422 | ||
![]() |
d7d6601b60 | ||
![]() |
bf95994c9e | ||
![]() |
a2d6ca0740 | ||
![]() |
1115bbb706 | ||
![]() |
0b17ed4322 | ||
![]() |
bcc85a5b3f | ||
![]() |
5b26f1a30b | ||
![]() |
63677d5027 | ||
![]() |
96579c1be4 | ||
![]() |
af58b76f0c | ||
![]() |
7879f31f63 | ||
![]() |
2ca7b41982 | ||
![]() |
8bdc0f8fde | ||
![]() |
0bb9e9cb6c | ||
![]() |
bdc2a72790 | ||
![]() |
073bd96b17 | ||
![]() |
37f22a9dc2 | ||
![]() |
bc3c5b3f66 | ||
![]() |
c61a62cc85 | ||
![]() |
66a6583ec4 | ||
![]() |
d24b37e2f2 | ||
![]() |
161c155de6 | ||
![]() |
dd59233dd4 | ||
![]() |
e9c74d4d9c | ||
![]() |
b37adb4546 | ||
![]() |
a4e99209be | ||
![]() |
45aa8f30e5 | ||
![]() |
60a7b15700 | ||
![]() |
df2ff8b3b7 | ||
![]() |
da8c8f80f1 | ||
![]() |
eda3de11fe | ||
![]() |
7d7de14827 | ||
![]() |
1c709da92c | ||
![]() |
a9092497b2 | ||
![]() |
b1f530e64a | ||
![]() |
8c086b77d3 | ||
![]() |
c0fdfe87be | ||
![]() |
6cfd840283 | ||
![]() |
d80cde1136 | ||
![]() |
bea4b06675 | ||
![]() |
88bc33b5a4 | ||
![]() |
2db36bb824 | ||
![]() |
dd689b1883 | ||
![]() |
641abd13f5 | ||
![]() |
a0b3a7fe5d | ||
![]() |
a0486f581f | ||
![]() |
36161137ec | ||
![]() |
c9927edbd1 | ||
![]() |
f0a3c05a9a | ||
![]() |
d6eb82c457 | ||
![]() |
7f47307307 | ||
![]() |
165dd3dfd1 | ||
![]() |
171727c9db | ||
![]() |
1492814ec9 | ||
![]() |
9b1225fe4b | ||
![]() |
595d88e42e | ||
![]() |
0e207d7401 | ||
![]() |
5920d6c9e8 | ||
![]() |
44fd3c10fa | ||
![]() |
91ab8a681c | ||
![]() |
d843bdb451 | ||
![]() |
2884fc711c | ||
![]() |
8ea2081270 | ||
![]() |
2296329962 | ||
![]() |
fc1bff2160 | ||
![]() |
e61c2b616e | ||
![]() |
ea1e8ac2c3 | ||
![]() |
1082175089 | ||
![]() |
90d64089a6 | ||
![]() |
b689628975 | ||
![]() |
f8e701aa07 | ||
![]() |
d855328c52 | ||
![]() |
bafe05117b | ||
![]() |
4b7c181040 | ||
![]() |
a3721ae784 | ||
![]() |
ae62c528aa | ||
![]() |
e6522769d0 | ||
![]() |
cab93e8c5e | ||
![]() |
ac78ecb298 | ||
![]() |
51876f788f | ||
![]() |
82c32d4442 | ||
![]() |
22b4905828 | ||
![]() |
0cb8ece336 | ||
![]() |
d2429da044 | ||
![]() |
92d867fbaa | ||
![]() |
a5e3986eb9 | ||
![]() |
8f7f4ee9f9 | ||
![]() |
c23597066a | ||
![]() |
dab5e08910 | ||
![]() |
c35deab283 | ||
![]() |
7c36ccfd9c | ||
![]() |
402d51ec6e | ||
![]() |
ca58211676 | ||
![]() |
97c6ba5334 | ||
![]() |
f1f2f250be | ||
![]() |
7b19e9a2bd | ||
![]() |
ed8010c92c | ||
![]() |
41580e5519 | ||
![]() |
1875e2df62 | ||
![]() |
347123d961 | ||
![]() |
f5ad07c2b0 | ||
![]() |
62695af9c6 | ||
![]() |
3b1c3d564b | ||
![]() |
b28a140b48 | ||
![]() |
75bba4a091 | ||
![]() |
cfb3c23003 | ||
![]() |
2cb87bab8e | ||
![]() |
1ddc3d6b58 | ||
![]() |
2fa48d7441 | ||
![]() |
545367db90 | ||
![]() |
d67e02cbcb | ||
![]() |
d3beb7ca3f | ||
![]() |
f951e1a621 |
27
.circleci/config.yml
Normal file
27
.circleci/config.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
working_directory: ~/code
|
||||
docker:
|
||||
- image: bitriseio/android-ndk
|
||||
environment:
|
||||
JVM_OPTS: -Xmx3200m
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
||||
- run:
|
||||
name: Download Dependencies
|
||||
command: ./gradlew androidDependencies
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.gradle
|
||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
||||
- run:
|
||||
name: Run Tests
|
||||
command: ./gradlew test
|
||||
- store_artifacts:
|
||||
path: app/build/reports
|
||||
destination: reports
|
||||
- store_test_results:
|
||||
path: app/build/test-results
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,8 +1,7 @@
|
||||
.gradle
|
||||
/build
|
||||
*.iml
|
||||
/.idea/libraries
|
||||
/.idea/workspace.xml
|
||||
/.idea
|
||||
/local.properties
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
28
README.md
28
README.md
@@ -1,32 +1,42 @@
|
||||
# Monerujo
|
||||
Another Android Monero Wallet
|
||||
Another Android Monero Wallet for Monero
|
||||
**(not
|
||||
Monero Classic,
|
||||
Monero-Classic,
|
||||
Monero Zero,
|
||||
Monero Original,
|
||||
Monero C,
|
||||
Monero V)**
|
||||
|
||||
### QUICKSTART
|
||||
- Download the APK for the most current release [here](https://github.com/m2049r/xmrwallet/releases) and install it
|
||||
- Alternatively add our F-Droid repo https://f-droid.monerujo.io/fdroid/repo with fingerpint ```A8 2C 68 E1 4A F0 AA 6A 2E C2 0E 6B 27 2E FF 25 E5 A0 38 F3 F6 58 84 31 6E 0F 5E 0D 91 E7 B7 13``` to your F-Droid client
|
||||
- Run the App and select "Generate Wallet" to create a new wallet or recover a wallet
|
||||
- Advanced users can copy over synced wallet files (all files) onto sdcard in directory Monerujo (created first time App is started)
|
||||
- See the [FAQ](doc/FAQ.md)
|
||||
|
||||
## Translations
|
||||
Help us translate Monerujo! You can find instructions [On Taiga](https://taiga.getmonero.org/project/erciccione-monero-localization/wiki/monerujo), and if you need help/support, open an issue or contact the Localization Workgroup. You can find us on the freenode channel `#monero-translations`, also relayed on [MatterMost](https://mattermost.getmonero.org/monero/channels/monero-translations), and matrix/riot.
|
||||
|
||||
### Disclaimer
|
||||
You may lose all your Moneroj if you use this App. Be cautious when spending on the mainnet.
|
||||
|
||||
### Random Notes
|
||||
- Based off monero v0.11.0.0 with PR #2289 applied
|
||||
- Based off monero v0.11.1.0
|
||||
- currently only android32 (runs on 64-bit as well)
|
||||
- works on the testnet & mainnet
|
||||
- sync is slow due to 32-bit architecture
|
||||
- use your own daemon - it's easy
|
||||
- screen stays on until first sync is complete
|
||||
- saves wallet only on first sync and when sending transactions or editing notes
|
||||
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
|
||||
|
||||
### TODO
|
||||
- more sensible error dialogs
|
||||
- see taiga.getmonero.org & issues on github
|
||||
|
||||
### Issues / Pitfalls
|
||||
- The backups folder is now called "backups" and not ".backups" - which in most file explorers was a hidden folder
|
||||
- Wallets are now created directly in the "monerujo" folder, and not in the ".new" folder as before
|
||||
- You may want to check the old folders with a file browsing app and delete the ".new" and ".backups" folders AFTER moving neccessary wallet files to the new locations. Or simply make new backups from within Monerujo.
|
||||
- Users of Zenfone MAX & Zenfone 2 Laser (possibly others) **MUST** use the armeabi-v7a APK as the arm64-v8a build uses hardware AES
|
||||
functionality these models don't have.
|
||||
- You should backup your wallet files in the "monerujo" folder periodically.
|
||||
- Also note, that on some devices the backups will only be visible on a PC over USB after a reboot of the device (it's an Android bug/feature)
|
||||
- Created wallets on a private testnet are unusable because the restore height is set to that
|
||||
of the "real" testnet. After creating a new wallet, make a **new** one by recovering from the seed.
|
||||
@@ -36,8 +46,8 @@ The official monero client shows the same behaviour.
|
||||
No need to build. Binaries are included:
|
||||
|
||||
- openssl-1.0.2l
|
||||
- monero-v0.11.0.0 + pull requests #2289
|
||||
- boost_1_64_0
|
||||
- monero-v0.12
|
||||
- boost_1_58_0
|
||||
|
||||
If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md)
|
||||
|
||||
|
@@ -60,9 +60,13 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_wserialization.a)
|
||||
|
||||
#############
|
||||
# Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct)
|
||||
# Monero
|
||||
#############
|
||||
|
||||
add_library(wallet_api STATIC IMPORTED)
|
||||
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet_api.a)
|
||||
|
||||
add_library(wallet STATIC IMPORTED)
|
||||
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
|
||||
@@ -91,11 +95,9 @@ add_library(ringct STATIC IMPORTED)
|
||||
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
|
||||
|
||||
#####
|
||||
|
||||
add_library(p2p STATIC IMPORTED)
|
||||
set_target_properties(p2p PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.a)
|
||||
add_library(ringct_basic STATIC IMPORTED)
|
||||
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct_basic.a)
|
||||
|
||||
add_library(blockchain_db STATIC IMPORTED)
|
||||
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
||||
@@ -113,7 +115,6 @@ add_library(unbound STATIC IMPORTED)
|
||||
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
|
||||
|
||||
####
|
||||
add_library(epee STATIC IMPORTED)
|
||||
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libepee.a)
|
||||
@@ -122,9 +123,21 @@ add_library(blocks STATIC IMPORTED)
|
||||
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblocks.a)
|
||||
|
||||
add_library(miniupnpc STATIC IMPORTED)
|
||||
set_target_properties(miniupnpc PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libminiupnpc.a)
|
||||
add_library(checkpoints STATIC IMPORTED)
|
||||
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcheckpoints.a)
|
||||
|
||||
add_library(device STATIC IMPORTED)
|
||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
|
||||
add_library(multisig STATIC IMPORTED)
|
||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmultisig.a)
|
||||
|
||||
add_library(version STATIC IMPORTED)
|
||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||
|
||||
#############
|
||||
# System
|
||||
@@ -137,23 +150,26 @@ include_directories( ${EXTERNAL_LIBS_DIR}/monero/include )
|
||||
message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR})
|
||||
|
||||
target_link_libraries( monerujo
|
||||
|
||||
wallet_api
|
||||
wallet
|
||||
cryptonote_core
|
||||
cryptonote_basic
|
||||
mnemonics
|
||||
ringct
|
||||
ringct_basic
|
||||
common
|
||||
cncrypto
|
||||
|
||||
blockchain_db
|
||||
lmdb
|
||||
easylogging
|
||||
unbound
|
||||
p2p
|
||||
|
||||
epee
|
||||
blocks
|
||||
miniupnpc
|
||||
checkpoints
|
||||
device
|
||||
multisig
|
||||
version
|
||||
|
||||
boost_chrono
|
||||
boost_date_time
|
||||
|
@@ -1,15 +1,14 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'witness'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '26.0.2'
|
||||
buildToolsVersion '27.0.3'
|
||||
defaultConfig {
|
||||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 31
|
||||
versionName "1.1.3-alpha"
|
||||
versionCode 95
|
||||
versionName "1.5.5 'Accounts Nacho'"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
@@ -17,9 +16,6 @@ android {
|
||||
arguments '-DANDROID_STL=c++_shared'
|
||||
}
|
||||
}
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a'
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -27,44 +23,59 @@ android {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
reset()
|
||||
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
universalApk true
|
||||
}
|
||||
}
|
||||
|
||||
// Map for the version code that gives each ABI a value.
|
||||
def abiCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
|
||||
|
||||
// APKs for the same app that all have the same version information.
|
||||
android.applicationVariants.all { variant ->
|
||||
// Assigns a different version code for each output APK.
|
||||
variant.outputs.all {
|
||||
output ->
|
||||
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
|
||||
output.versionCodeOverride = abiCodes.get(abiName, 0) + 10 * variant.versionCode
|
||||
|
||||
if (abiName == null) abiName = "universal"
|
||||
def v = "${variant.versionName}".replaceFirst(" .*\$", "").replace(".", "x")
|
||||
outputFileName = "$rootProject.ext.apkName-" + v + "_" + abiName + ".apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:appcompat-v7:25.4.0'
|
||||
compile 'com.android.support:design:25.4.0'
|
||||
compile 'com.android.support:support-v4:25.4.0'
|
||||
compile 'com.android.support:recyclerview-v7:25.4.0'
|
||||
compile 'com.android.support:cardview-v7:25.4.0'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
compile 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
}
|
||||
implementation 'com.android.support:appcompat-v7:25.4.0'
|
||||
implementation 'com.android.support:design:25.4.0'
|
||||
implementation 'com.android.support:support-v4:25.4.0'
|
||||
implementation 'com.android.support:recyclerview-v7:25.4.0'
|
||||
implementation 'com.android.support:cardview-v7:25.4.0'
|
||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'com.android.support:appcompat-v7:70551e62660db15b790c5275f56b9de4dd9407d1494d07c8f3dd5698f3638677',
|
||||
'com.android.support:design:3f409bf2019967ffc344cfaf11e52131fac982468a1707aaeb25bf3c52838966',
|
||||
'com.android.support:support-v4:ee44c481a1f4d6978568e223e8125379b52b2ececdd53450e09ebae144bd377d',
|
||||
'com.android.support:recyclerview-v7:a2fe121f9d01ed8980e97095b4a3fe9700a0aa0a7d4b0f8c594f765ad8455a0d',
|
||||
'com.android.support:cardview-v7:f3fbbe1fcfdbec7333c6a2c516c5fd511a909d1975271818e268d6fe297d8c70',
|
||||
'com.android.support.constraint:constraint-layout:b0c688cc2b7172608f8153a689d746da40f71e52d7e2fe2bfd9df2f92db77085',
|
||||
'me.dm7.barcodescanner:zxing:d43973c9527c23fa8e6d338c6a2c458e373ce1ac6bcaa3bc41d11ae49116000d',
|
||||
'com.android.support:support-annotations:a774272036941b4e912eb426d70c848bde7f06a3bf5fb491f75a427dc6595270',
|
||||
'com.android.support:support-vector-drawable:077009d13882ee96f061e4bc2dbe7cce7ae1762d8297592a787ff741afbfb1f2',
|
||||
'com.android.support:animated-vector-drawable:628ab1d56a6ee4cbedf32617af8b2a1fe02964ed0628e8f898cc09ddba6e1835',
|
||||
'com.android.support:transition:848270144fb180efd2bf928a00ed176dbbc5290badfd638390ffba90088df8b3',
|
||||
'com.android.support:support-compat:54019c63614ce08b02d7b9605490cd2b29ba5b2505f394a9517450b5f72b30ca',
|
||||
'com.android.support:support-media-compat:566a161d9cb0083ef62a53e46b71ce5b3d455b8635b1a0a4ae28d96d4b583de8',
|
||||
'com.android.support:support-core-utils:34b8437dfa95ff28d29cf57ffa3b1354a9fa9bfe4059f0fd5ce2f5e4326a1748',
|
||||
'com.android.support:support-core-ui:e72ae29b823889686cff6fcb948d6745c2baf6d4c2af4fdffa1ec1e42e3833a3',
|
||||
'com.android.support:support-fragment:316d35d4d2d2902057efad104a73e4bdb50bee260a7075678185b8cd71170945',
|
||||
'com.android.support.constraint:constraint-layout-solver:8c62525a9bc5cff5633a96cb9b32fffeccaf41b8841aa87fc22607070dea9b8d',
|
||||
'me.dm7.barcodescanner:core:a5c8a704089b58029db166172ed8e55d756877d010a85a0b1c94fdc96ffb8f9a',
|
||||
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
||||
]
|
||||
implementation "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
|
||||
implementation "com.jakewharton.timber:timber:$rootProject.ext.timberVersion"
|
||||
|
||||
implementation 'com.nulab-inc:zxcvbn:1.2.3'
|
||||
|
||||
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
||||
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
||||
testImplementation 'org.json:json:20140107'
|
||||
testImplementation 'net.jodah:concurrentunit:0.4.2'
|
||||
}
|
||||
|
BIN
app/src/debug/res/mipmap-hdpi/ic_launcher.png
Executable file
BIN
app/src/debug/res/mipmap-hdpi/ic_launcher.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
BIN
app/src/debug/res/mipmap-mdpi/ic_launcher.png
Executable file
BIN
app/src/debug/res/mipmap-mdpi/ic_launcher.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/debug/res/mipmap-xhdpi/ic_launcher.png
Executable file
BIN
app/src/debug/res/mipmap-xhdpi/ic_launcher.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
Executable file
BIN
app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
Executable file
BIN
app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
4
app/src/debug/res/values/strings.xml
Normal file
4
app/src/debug/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">monerujo - Debug</string>
|
||||
</resources>
|
@@ -7,12 +7,14 @@
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:name=".XmrWalletApplication"
|
||||
android:theme="@style/MyMaterialTheme">
|
||||
|
||||
<activity
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
||||
#define XMRWALLET_WALLET_LIB_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
/*
|
||||
#include <android/log.h>
|
||||
|
||||
@@ -27,13 +28,13 @@
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
||||
*/
|
||||
|
||||
jfieldID getHandleField(JNIEnv *env, jobject obj, const char* fieldName = "handle") {
|
||||
jfieldID getHandleField(JNIEnv *env, jobject obj, const char *fieldName = "handle") {
|
||||
jclass c = env->GetObjectClass(obj);
|
||||
return env->GetFieldID(c, fieldName, "J"); // of type long
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *getHandle(JNIEnv *env, jobject obj, const char* fieldName = "handle") {
|
||||
template<typename T>
|
||||
T *getHandle(JNIEnv *env, jobject obj, const char *fieldName = "handle") {
|
||||
jlong handle = env->GetLongField(obj, getHandleField(env, obj, fieldName));
|
||||
return reinterpret_cast<T *>(handle);
|
||||
}
|
||||
@@ -42,10 +43,35 @@ void setHandleFromLong(JNIEnv *env, jobject obj, jlong handle) {
|
||||
env->SetLongField(obj, getHandleField(env, obj), handle);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
void setHandle(JNIEnv *env, jobject obj, T *t) {
|
||||
jlong handle = reinterpret_cast<jlong>(t);
|
||||
setHandleFromLong(env, obj, handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// from monero-core crypto/hash-ops.h - avoid #including monero code here
|
||||
enum {
|
||||
HASH_SIZE = 32,
|
||||
HASH_DATA_AREA = 136
|
||||
};
|
||||
|
||||
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed);
|
||||
|
||||
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
||||
cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/);
|
||||
}
|
||||
|
||||
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*/);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //XMRWALLET_WALLET_LIB_H
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
public interface OnBackPressedListener {
|
||||
boolean onBackPressed();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@ import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -30,21 +29,21 @@ import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler {
|
||||
static final String TAG = "ScannerFragment";
|
||||
|
||||
private Listener activityCallback;
|
||||
private OnScannedListener onScannedListener;
|
||||
|
||||
public interface Listener {
|
||||
boolean onAddressScanned(String uri);
|
||||
public interface OnScannedListener {
|
||||
boolean onScanned(String qrCode);
|
||||
}
|
||||
|
||||
private ZXingScannerView mScannerView;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreateView");
|
||||
Timber.d("onCreateView");
|
||||
mScannerView = new ZXingScannerView(getActivity());
|
||||
return mScannerView;
|
||||
}
|
||||
@@ -52,20 +51,15 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume");
|
||||
Timber.d("onResume");
|
||||
mScannerView.setResultHandler(this);
|
||||
mScannerView.startCamera();
|
||||
}
|
||||
|
||||
static final String QR_SCHEME = "monero:";
|
||||
static final String QR_PAYMENTID = "tx_payment_id";
|
||||
static final String QR_AMOUNT = "tx_amount";
|
||||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
|
||||
(rawResult.getText().startsWith(QR_SCHEME))) {
|
||||
if (activityCallback.onAddressScanned(rawResult.getText())) {
|
||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE)) {
|
||||
if (onScannedListener.onScanned(rawResult.getText())) {
|
||||
return;
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show();
|
||||
@@ -91,7 +85,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
Log.d(TAG, "onPause");
|
||||
Timber.d("onPause");
|
||||
mScannerView.stopCamera();
|
||||
super.onPause();
|
||||
}
|
||||
@@ -99,11 +93,11 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
if (context instanceof OnScannedListener) {
|
||||
this.onScannedListener = (OnScannedListener) context;
|
||||
} else {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
app/src/main/java/com/m2049r/xmrwallet/SecureActivity.java
Normal file
39
app/src/main/java/com/m2049r/xmrwallet/SecureActivity.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams;
|
||||
|
||||
public abstract class SecureActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!BuildConfig.DEBUG) {
|
||||
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -30,11 +30,14 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.Toolbar;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
@@ -44,7 +47,6 @@ import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class TxFragment extends Fragment {
|
||||
static final String TAG = "TxFragment";
|
||||
|
||||
static public final String ARG_INFO = "info";
|
||||
|
||||
@@ -57,6 +59,7 @@ public class TxFragment extends Fragment {
|
||||
TS_FORMATTER.setTimeZone(tz);
|
||||
}
|
||||
|
||||
private TextView tvAccount;
|
||||
private TextView tvTxTimestamp;
|
||||
private TextView tvTxId;
|
||||
private TextView tvTxKey;
|
||||
@@ -69,12 +72,24 @@ public class TxFragment extends Fragment {
|
||||
private TextView etTxNotes;
|
||||
private Button bTxNotes;
|
||||
|
||||
// XMRTO stuff
|
||||
private View cvXmrTo;
|
||||
private TextView tvTxXmrToKey;
|
||||
private TextView tvDestinationBtc;
|
||||
private TextView tvTxAmountBtc;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.fragment_tx_info, container, false);
|
||||
|
||||
cvXmrTo = view.findViewById(R.id.cvXmrTo);
|
||||
tvTxXmrToKey = (TextView) view.findViewById(R.id.tvTxXmrToKey);
|
||||
tvDestinationBtc = (TextView) view.findViewById(R.id.tvDestinationBtc);
|
||||
tvTxAmountBtc = (TextView) view.findViewById(R.id.tvTxAmountBtc);
|
||||
|
||||
tvAccount = (TextView) view.findViewById(R.id.tvAccount);
|
||||
tvTxTimestamp = (TextView) view.findViewById(R.id.tvTxTimestamp);
|
||||
tvTxId = (TextView) view.findViewById(R.id.tvTxId);
|
||||
tvTxKey = (TextView) view.findViewById(R.id.tvTxKey);
|
||||
@@ -95,7 +110,16 @@ public class TxFragment extends Fragment {
|
||||
info.notes = null; // force reload on next view
|
||||
bTxNotes.setEnabled(false);
|
||||
etTxNotes.setEnabled(false);
|
||||
activityCallback.onSetNote(info.hash, etTxNotes.getText().toString());
|
||||
userNotes.setNote(etTxNotes.getText().toString());
|
||||
activityCallback.onSetNote(info.hash, userNotes.txNotes);
|
||||
}
|
||||
});
|
||||
|
||||
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
|
||||
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -167,8 +191,7 @@ public class TxFragment extends Fragment {
|
||||
sb.append("-");
|
||||
}
|
||||
sb.append("\n\n");
|
||||
//Helper.clipBoardCopy(getActivity(), getString(R.string.tx_copy_label), sb.toString());
|
||||
//Toast.makeText(getActivity(), getString(R.string.tx_copy_message), Toast.LENGTH_SHORT).show();
|
||||
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());
|
||||
@@ -177,12 +200,14 @@ public class TxFragment extends Fragment {
|
||||
}
|
||||
|
||||
TransactionInfo info = null;
|
||||
UserNotes userNotes = null;
|
||||
|
||||
void loadNotes(TransactionInfo info) {
|
||||
if (info.notes == null) {
|
||||
if ((userNotes == null) || (info.notes == null)) {
|
||||
info.notes = activityCallback.getTxNotes(info.hash);
|
||||
}
|
||||
etTxNotes.setText(info.notes);
|
||||
userNotes = new UserNotes(info.notes);
|
||||
etTxNotes.setText(userNotes.note);
|
||||
}
|
||||
|
||||
private void setTxColour(int clr) {
|
||||
@@ -199,6 +224,8 @@ public class TxFragment extends Fragment {
|
||||
activityCallback.setSubtitle(getString(R.string.tx_title));
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
||||
|
||||
tvAccount.setText("" + info.subaddrAccount);
|
||||
|
||||
tvTxTimestamp.setText(TS_FORMATTER.format(new Date(info.timestamp * 1000)));
|
||||
tvTxId.setText(info.hash);
|
||||
tvTxKey.setText(info.txKey.isEmpty() ? "-" : info.txKey);
|
||||
@@ -213,9 +240,6 @@ public class TxFragment extends Fragment {
|
||||
String sign = (info.direction == TransactionInfo.Direction.Direction_In ? "+" : "-");
|
||||
|
||||
long realAmount = info.amount;
|
||||
if (info.isPending) {
|
||||
realAmount = realAmount - info.fee;
|
||||
}
|
||||
tvTxAmount.setText(sign + Wallet.getDisplayAmount(realAmount));
|
||||
|
||||
if ((info.fee > 0)) {
|
||||
@@ -268,8 +292,21 @@ public class TxFragment extends Fragment {
|
||||
tvTxTransfers.setText(sb.toString());
|
||||
tvDestination.setText(dstSb.toString());
|
||||
this.info = info;
|
||||
showBtcInfo();
|
||||
}
|
||||
|
||||
void showBtcInfo() {
|
||||
if (userNotes.xmrtoKey != null) {
|
||||
cvXmrTo.setVisibility(View.VISIBLE);
|
||||
tvTxXmrToKey.setText(userNotes.xmrtoKey);
|
||||
tvDestinationBtc.setText(userNotes.xmrtoDestination);
|
||||
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " BTC");
|
||||
} else {
|
||||
cvXmrTo.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -309,4 +346,4 @@ public class TxFragment extends Fragment {
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r et al.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class XmrWalletApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(new Timber.DebugTree());
|
||||
}
|
||||
}
|
||||
}
|
201
app/src/main/java/com/m2049r/xmrwallet/data/BarcodeData.java
Normal file
201
app/src/main/java/com/m2049r/xmrwallet/data/BarcodeData.java
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import com.m2049r.xmrwallet.model.NetworkType;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class BarcodeData {
|
||||
public static final String XMR_SCHEME = "monero:";
|
||||
public static final String XMR_PAYMENTID = "tx_payment_id";
|
||||
public static final String XMR_AMOUNT = "tx_amount";
|
||||
|
||||
static final String BTC_SCHEME = "bitcoin:";
|
||||
static final String BTC_AMOUNT = "amount";
|
||||
|
||||
public enum Asset {
|
||||
XMR, BTC
|
||||
}
|
||||
|
||||
public Asset asset = null;
|
||||
public String address = null;
|
||||
public String paymentId = null;
|
||||
public String amount = null;
|
||||
|
||||
public BarcodeData(Asset asset, String address) {
|
||||
this.asset = asset;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public BarcodeData(Asset asset, String address, String amount) {
|
||||
this.asset = asset;
|
||||
this.address = address;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public BarcodeData(Asset asset, String address, String paymentId, String amount) {
|
||||
this.asset = asset;
|
||||
this.address = address;
|
||||
this.paymentId = paymentId;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
static public BarcodeData fromQrCode(String qrCode) {
|
||||
// check for monero uri
|
||||
BarcodeData bcData = parseMoneroUri(qrCode);
|
||||
// check for naked monero address / integrated address
|
||||
if (bcData == null) {
|
||||
bcData = parseMoneroNaked(qrCode);
|
||||
}
|
||||
// check for btc uri
|
||||
if (bcData == null) {
|
||||
bcData = parseBitcoinUri(qrCode);
|
||||
}
|
||||
// check for naked btc addres
|
||||
if (bcData == null) {
|
||||
bcData = parseBitcoinNaked(qrCode);
|
||||
}
|
||||
return bcData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and decode a monero scheme string. It is here because it needs to validate the data.
|
||||
*
|
||||
* @param uri String containing a monero URL
|
||||
* @return BarcodeData object or null if uri not valid
|
||||
*/
|
||||
|
||||
static public BarcodeData parseMoneroUri(String uri) {
|
||||
Timber.d("parseMoneroUri=%s", uri);
|
||||
|
||||
if (uri == null) return null;
|
||||
|
||||
if (!uri.startsWith(XMR_SCHEME)) return null;
|
||||
|
||||
String noScheme = uri.substring(XMR_SCHEME.length());
|
||||
Uri monero = Uri.parse(noScheme);
|
||||
Map<String, String> parms = new HashMap<>();
|
||||
String query = monero.getQuery();
|
||||
if (query != null) {
|
||||
String[] args = query.split("&");
|
||||
for (String arg : args) {
|
||||
String[] namevalue = arg.split("=");
|
||||
if (namevalue.length == 0) {
|
||||
continue;
|
||||
}
|
||||
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
|
||||
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
|
||||
}
|
||||
}
|
||||
String address = monero.getPath();
|
||||
String paymentId = parms.get(XMR_PAYMENTID);
|
||||
String amount = parms.get(XMR_AMOUNT);
|
||||
if (amount != null) {
|
||||
try {
|
||||
Double.parseDouble(amount);
|
||||
} catch (NumberFormatException ex) {
|
||||
Timber.d(ex.getLocalizedMessage());
|
||||
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)) {
|
||||
Timber.d("address invalid");
|
||||
return null;
|
||||
}
|
||||
return new BarcodeData(Asset.XMR, address, paymentId, amount);
|
||||
}
|
||||
|
||||
static public BarcodeData parseMoneroNaked(String address) {
|
||||
Timber.d("parseMoneroNaked=%s", address);
|
||||
|
||||
if (address == null) return null;
|
||||
|
||||
if (!Wallet.isAddressValid(address)) {
|
||||
Timber.d("address invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BarcodeData(Asset.XMR, address);
|
||||
}
|
||||
|
||||
// bitcoin:mpQ84J43EURZHkCnXbyQ4PpNDLLBqdsMW2?amount=0.01
|
||||
static public BarcodeData parseBitcoinUri(String uri) {
|
||||
Timber.d("parseBitcoinUri=%s", uri);
|
||||
|
||||
if (uri == null) return null;
|
||||
|
||||
if (!uri.startsWith(BTC_SCHEME)) return null;
|
||||
|
||||
String noScheme = uri.substring(BTC_SCHEME.length());
|
||||
Uri bitcoin = Uri.parse(noScheme);
|
||||
Map<String, String> parms = new HashMap<>();
|
||||
String query = bitcoin.getQuery();
|
||||
if (query != null) {
|
||||
String[] args = query.split("&");
|
||||
for (String arg : args) {
|
||||
String[] namevalue = arg.split("=");
|
||||
if (namevalue.length == 0) {
|
||||
continue;
|
||||
}
|
||||
parms.put(Uri.decode(namevalue[0]).toLowerCase(),
|
||||
namevalue.length > 1 ? Uri.decode(namevalue[1]) : "");
|
||||
}
|
||||
}
|
||||
String address = bitcoin.getPath();
|
||||
String amount = parms.get(BTC_AMOUNT);
|
||||
if (amount != null) {
|
||||
try {
|
||||
Double.parseDouble(amount);
|
||||
} catch (NumberFormatException ex) {
|
||||
Timber.d(ex.getLocalizedMessage());
|
||||
return null; // we have an amount but its not a number!
|
||||
}
|
||||
}
|
||||
if (!BitcoinAddressValidator.validate(address)) {
|
||||
Timber.d("address invalid");
|
||||
return null;
|
||||
}
|
||||
return new BarcodeData(BarcodeData.Asset.BTC, address, amount);
|
||||
}
|
||||
|
||||
static public BarcodeData parseBitcoinNaked(String address) {
|
||||
Timber.d("parseBitcoinNaked=%s", address);
|
||||
|
||||
if (address == null) return null;
|
||||
|
||||
if (!BitcoinAddressValidator.validate(address)) {
|
||||
Timber.d("address invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BarcodeData(BarcodeData.Asset.BTC, address);
|
||||
}
|
||||
}
|
39
app/src/main/java/com/m2049r/xmrwallet/data/PendingTx.java
Normal file
39
app/src/main/java/com/m2049r/xmrwallet/data/PendingTx.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
|
||||
public class PendingTx {
|
||||
final public PendingTransaction.Status status;
|
||||
final public String error;
|
||||
final public long amount;
|
||||
final public long dust;
|
||||
final public long fee;
|
||||
final public String txId;
|
||||
final public long txCount;
|
||||
|
||||
public PendingTx(PendingTransaction pendingTransaction) {
|
||||
status = pendingTransaction.getStatus();
|
||||
error = pendingTransaction.getErrorString();
|
||||
amount = pendingTransaction.getAmount();
|
||||
dust = pendingTransaction.getDust();
|
||||
fee = pendingTransaction.getFee();
|
||||
txId = pendingTransaction.getFirstTxId();
|
||||
txCount = pendingTransaction.getTxCount();
|
||||
}
|
||||
}
|
@@ -14,36 +14,101 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.util;
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
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
|
||||
public class TxData implements Parcelable {
|
||||
public TxData(String dst_addr,
|
||||
|
||||
public TxData() {
|
||||
}
|
||||
|
||||
public TxData(TxData txData) {
|
||||
this.dstAddr = txData.dstAddr;
|
||||
this.paymentId = txData.paymentId;
|
||||
this.amount = txData.amount;
|
||||
this.mixin = txData.mixin;
|
||||
this.priority = txData.priority;
|
||||
}
|
||||
|
||||
public TxData(String dstAddr,
|
||||
String paymentId,
|
||||
long amount,
|
||||
int mixin,
|
||||
PendingTransaction.Priority priority) {
|
||||
this.dst_addr = dst_addr;
|
||||
this.dstAddr = dstAddr;
|
||||
this.paymentId = paymentId;
|
||||
this.amount = amount;
|
||||
this.mixin = mixin;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public String dst_addr;
|
||||
public String paymentId;
|
||||
public long amount;
|
||||
public int mixin;
|
||||
public PendingTransaction.Priority priority;
|
||||
public String getDestinationAddress() {
|
||||
return dstAddr;
|
||||
}
|
||||
|
||||
public String getPaymentId() {
|
||||
return paymentId;
|
||||
}
|
||||
|
||||
public long getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public int getMixin() {
|
||||
return mixin;
|
||||
}
|
||||
|
||||
public PendingTransaction.Priority getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setDestinationAddress(String dstAddr) {
|
||||
this.dstAddr = dstAddr;
|
||||
}
|
||||
|
||||
public void setPaymentId(String paymentId) {
|
||||
this.paymentId = paymentId;
|
||||
}
|
||||
|
||||
public void setAmount(long amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setMixin(int mixin) {
|
||||
this.mixin = mixin;
|
||||
}
|
||||
|
||||
public void setPriority(PendingTransaction.Priority priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public UserNotes getUserNotes() {
|
||||
return userNotes;
|
||||
}
|
||||
|
||||
public void setUserNotes(UserNotes userNotes) {
|
||||
this.userNotes = userNotes;
|
||||
}
|
||||
|
||||
private String dstAddr;
|
||||
private String paymentId;
|
||||
private long amount;
|
||||
private int mixin;
|
||||
private PendingTransaction.Priority priority;
|
||||
|
||||
private UserNotes userNotes;
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(dst_addr);
|
||||
out.writeString(dstAddr);
|
||||
out.writeString(paymentId);
|
||||
out.writeLong(amount);
|
||||
out.writeInt(mixin);
|
||||
@@ -61,8 +126,8 @@ public class TxData implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
private TxData(Parcel in) {
|
||||
dst_addr = in.readString();
|
||||
protected TxData(Parcel in) {
|
||||
dstAddr = in.readString();
|
||||
paymentId = in.readString();
|
||||
amount = in.readLong();
|
||||
mixin = in.readInt();
|
||||
@@ -78,8 +143,8 @@ public class TxData implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("dst_addr:");
|
||||
sb.append(dst_addr);
|
||||
sb.append("dstAddr:");
|
||||
sb.append(dstAddr);
|
||||
sb.append(",paymentId:");
|
||||
sb.append(paymentId);
|
||||
sb.append(",amount:");
|
||||
@@ -87,7 +152,7 @@ public class TxData implements Parcelable {
|
||||
sb.append(",mixin:");
|
||||
sb.append(mixin);
|
||||
sb.append(",priority:");
|
||||
sb.append(priority.toString());
|
||||
sb.append(String.valueOf(priority));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
98
app/src/main/java/com/m2049r/xmrwallet/data/TxDataBtc.java
Normal file
98
app/src/main/java/com/m2049r/xmrwallet/data/TxDataBtc.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
|
||||
public class TxDataBtc extends TxData {
|
||||
|
||||
private String xmrtoUuid;
|
||||
private String btcAddress;
|
||||
private double btcAmount;
|
||||
|
||||
public TxDataBtc() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TxDataBtc(TxDataBtc txDataBtc) {
|
||||
super(txDataBtc);
|
||||
}
|
||||
|
||||
public String getXmrtoUuid() {
|
||||
return xmrtoUuid;
|
||||
}
|
||||
|
||||
public void setXmrtoUuid(String xmrtoUuid) {
|
||||
this.xmrtoUuid = xmrtoUuid;
|
||||
}
|
||||
|
||||
public String getBtcAddress() {
|
||||
return btcAddress;
|
||||
}
|
||||
|
||||
public void setBtcAddress(String btcAddress) {
|
||||
this.btcAddress = btcAddress;
|
||||
}
|
||||
|
||||
public double getBtcAmount() {
|
||||
return btcAmount;
|
||||
}
|
||||
|
||||
public void setBtcAmount(double btcAmount) {
|
||||
this.btcAmount = btcAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeString(xmrtoUuid);
|
||||
out.writeString(btcAddress);
|
||||
out.writeDouble(btcAmount);
|
||||
}
|
||||
|
||||
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
|
||||
public static final Creator<TxDataBtc> CREATOR = new Creator<TxDataBtc>() {
|
||||
public TxDataBtc createFromParcel(Parcel in) {
|
||||
return new TxDataBtc(in);
|
||||
}
|
||||
|
||||
public TxDataBtc[] newArray(int size) {
|
||||
return new TxDataBtc[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected TxDataBtc(Parcel in) {
|
||||
super(in);
|
||||
xmrtoUuid = in.readString();
|
||||
btcAddress = in.readString();
|
||||
btcAmount = in.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(",xmrtoUuid:");
|
||||
sb.append(xmrtoUuid);
|
||||
sb.append(",btcAddress:");
|
||||
sb.append(btcAddress);
|
||||
sb.append(",btcAmount:");
|
||||
sb.append(btcAmount);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
112
app/src/main/java/com/m2049r/xmrwallet/data/WalletNode.java
Normal file
112
app/src/main/java/com/m2049r/xmrwallet/data/WalletNode.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2018 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.data;
|
||||
|
||||
import com.m2049r.xmrwallet.model.NetworkType;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class WalletNode {
|
||||
private final String name;
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final String user;
|
||||
private final String password;
|
||||
private final NetworkType networkType;
|
||||
|
||||
public WalletNode(String walletName, String daemon, NetworkType networkType) {
|
||||
if ((daemon == null) || daemon.isEmpty())
|
||||
throw new IllegalArgumentException("daemon is empty");
|
||||
this.name = walletName;
|
||||
String daemonAddress;
|
||||
String a[] = daemon.split("@");
|
||||
if (a.length == 1) { // no credentials
|
||||
daemonAddress = a[0];
|
||||
user = "";
|
||||
password = "";
|
||||
} else if (a.length == 2) { // credentials
|
||||
String userPassword[] = a[0].split(":");
|
||||
if (userPassword.length != 2)
|
||||
throw new IllegalArgumentException("User:Password invalid");
|
||||
user = userPassword[0];
|
||||
if (!user.isEmpty()) {
|
||||
password = userPassword[1];
|
||||
} else {
|
||||
password = "";
|
||||
}
|
||||
daemonAddress = a[1];
|
||||
} else {
|
||||
throw new IllegalArgumentException("Too many @");
|
||||
}
|
||||
|
||||
String da[] = daemonAddress.split(":");
|
||||
if ((da.length > 2) || (da.length < 1))
|
||||
throw new IllegalArgumentException("Too many ':' or too few");
|
||||
host = da[0];
|
||||
if (da.length == 2) {
|
||||
try {
|
||||
port = Integer.parseInt(da[1]);
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new IllegalArgumentException("Port not numeric");
|
||||
}
|
||||
} else {
|
||||
switch (networkType) {
|
||||
case NetworkType_Mainnet:
|
||||
port = 18081;
|
||||
break;
|
||||
case NetworkType_Testnet:
|
||||
port = 28081;
|
||||
break;
|
||||
case NetworkType_Stagenet:
|
||||
port = 38081;
|
||||
break;
|
||||
default:
|
||||
port = 0;
|
||||
}
|
||||
}
|
||||
this.networkType = networkType;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public NetworkType getNetworkType() {
|
||||
return networkType;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return host + ":" + port;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public SocketAddress getSocketAddress() {
|
||||
return new InetSocketAddress(host, port);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return !host.isEmpty();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user