mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-15 01:10:50 +02:00
Compare commits
84 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5b38cc438c | ||
![]() |
1eac363102 | ||
![]() |
e51425bc2e | ||
![]() |
f5535dbefa | ||
![]() |
2d42a0287d | ||
![]() |
2ebb9d0650 | ||
![]() |
30792c53c0 | ||
![]() |
3846a0c391 | ||
![]() |
c66ebd654a | ||
![]() |
186ed5cd39 | ||
![]() |
e39cd1c988 | ||
![]() |
39d9c4d0c3 | ||
![]() |
e4562f07a4 | ||
![]() |
b3ea4540a1 | ||
![]() |
ea7c7d2fdb | ||
![]() |
8ff8be6f60 | ||
![]() |
b5ded700fe | ||
![]() |
a5527d4efd | ||
![]() |
a007810824 | ||
![]() |
a634cf18b1 | ||
![]() |
0b2fa08df8 | ||
![]() |
191aa6ac22 | ||
![]() |
a82a90575d | ||
![]() |
2e04046f50 | ||
![]() |
c11d577c5f | ||
![]() |
74b2dd209c | ||
![]() |
cb1d541474 | ||
![]() |
807d217aac | ||
![]() |
0421bcfac3 | ||
![]() |
b6c4e06fda | ||
![]() |
3ee8343074 | ||
![]() |
110621824a | ||
![]() |
7194580fbe | ||
![]() |
48dcd37740 | ||
![]() |
8e619756b9 | ||
![]() |
6c6b47db7d | ||
![]() |
a126844272 | ||
![]() |
9b3086ff2e | ||
![]() |
89d1842d59 | ||
![]() |
d44067e952 | ||
![]() |
0370eaa619 | ||
![]() |
35c393495a | ||
![]() |
f19618e017 | ||
![]() |
3a68802ae7 | ||
![]() |
344eeb7a3b | ||
![]() |
4ad58684b4 | ||
![]() |
30e35a895d | ||
![]() |
37414be4bf | ||
![]() |
a37ca4c0e5 | ||
![]() |
408b1a68d0 | ||
![]() |
40da44222e | ||
![]() |
b0efdca928 | ||
![]() |
d61198b47f | ||
![]() |
62433f6e10 | ||
![]() |
c9ae39508f | ||
![]() |
44836a24bb | ||
![]() |
80e60bd0c8 | ||
![]() |
9f38b957e1 | ||
![]() |
032aa24ab5 | ||
![]() |
afc45e1cbc | ||
![]() |
bd598deddd | ||
![]() |
952fb3a7f1 | ||
![]() |
fb62074d20 | ||
![]() |
56132e26ed | ||
![]() |
3239bdeb33 | ||
![]() |
142885821e | ||
![]() |
34941c599a | ||
![]() |
58c8f1896c | ||
![]() |
6611539491 | ||
![]() |
69729e5257 | ||
![]() |
535158c5e9 | ||
![]() |
61e2d880c2 | ||
![]() |
72889fcdde | ||
![]() |
905ee8b8a9 | ||
![]() |
81a9aa6938 | ||
![]() |
046238a29f | ||
![]() |
9751825ed7 | ||
![]() |
c19ee65dd1 | ||
![]() |
282f00959d | ||
![]() |
104a6063a3 | ||
![]() |
95e47e3407 | ||
![]() |
cb5795e64b | ||
![]() |
746da913f0 | ||
![]() |
2682399600 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.gradle
|
||||||
|
build
|
2
.idea/.gitignore
generated
vendored
Normal file
2
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
workspace.xml
|
||||||
|
markdown-navigator*
|
10
.idea/libraries/core_1_9_8.xml
generated
Normal file
10
.idea/libraries/core_1_9_8.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="core-1.9.8">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/jars/classes.jar!/" />
|
||||||
|
<root url="file://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/res" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
11
.idea/libraries/core_3_3_0.xml
generated
Normal file
11
.idea/libraries/core_3_3_0.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="core-3.3.0">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/73c49077166faa4c3c0059c5f583d1d7bd1475fe/core-3.3.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/39d966e052e28fc7d83793b02e0af97ccf955745/core-3.3.0-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
10
.idea/libraries/zxing_1_9_8.xml
generated
Normal file
10
.idea/libraries/zxing_1_9_8.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="zxing-1.9.8">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/jars/classes.jar!/" />
|
||||||
|
<root url="file://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/res" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
3068
.idea/workspace.xml
generated
3068
.idea/workspace.xml
generated
File diff suppressed because it is too large
Load Diff
52
README.md
52
README.md
@@ -3,49 +3,43 @@ Another Android Monero Wallet
|
|||||||
|
|
||||||
### QUICKSTART
|
### QUICKSTART
|
||||||
- Download APK (Release) and install it
|
- Download APK (Release) and install it
|
||||||
- Copy over synced wallet (all three files) onto sdcard in directory Monerujo (created first time app is started)
|
- Run the App and select "Generate Wallet" to create a new wallet or recover a wallet
|
||||||
- Start app (again)
|
- Advanced users could copy over synced wallet files (all files) onto sdcard in directory Monerujo (created first time App is started)
|
||||||
- see the [FAQ](doc/FAQ.md)
|
- see the [FAQ](doc/FAQ.md)
|
||||||
|
|
||||||
### Disclaimer
|
### Disclaimer
|
||||||
This is my first serious Android App.
|
You may loose all your Moneroj if you use this App. Be cautious when spending on mainnet.
|
||||||
|
|
||||||
### Notes
|
### Random Notes
|
||||||
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
|
- Based off monero v0.10.3.1 with pull requests #2238, #2239 and #2289 applied => so can be used in mainnet!
|
||||||
- Special thanks to /u/gkruja for inspiration to pick this project up again
|
- currently only android32 (runs on 64-bit as well)
|
||||||
- Based off monero v0.10.3.1 with pull requests #2238 & #2239 applied => so can be used in mainnet!
|
- works in testnet & mainnet
|
||||||
- currently only android32
|
- takes forever to sync due to 32-bit architecture
|
||||||
- sorry for my messups in github
|
|
||||||
- this is more of a proof of concept
|
|
||||||
- currently only use is checking incoming/outgoing transactions
|
|
||||||
- works in testnet & mainnet (please use your own daemons)
|
|
||||||
- takes forever to sync on mainnet (even with own daemon)
|
|
||||||
- use your own daemon - it's easy
|
- use your own daemon - it's easy
|
||||||
- screen stays on until first sync is complete
|
- 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
|
### TODO
|
||||||
- don't have the screen on for first sync - use IntentService with WakeLock instead?
|
- wallet backup functions
|
||||||
- make it pretty
|
- review visibility of methods/classes
|
||||||
- show current block height - is that relevant?
|
- more sensible error dialogs
|
||||||
- License Dialog
|
- check licenses of included libraries; License Dialog
|
||||||
- support for right-to-left layouts
|
|
||||||
- visibility of methods/classes
|
|
||||||
- adjust layout so we can use bigger font sizes
|
|
||||||
- sensible error dialogs (e.g. when no write permissions granted) instead of just crashing on purpose
|
|
||||||
- sensible loading/saving progress bars instead of just freezing up
|
|
||||||
- spend monero - not so difficult with wallet api
|
|
||||||
- figure out how to make it all flow better (loading/saving takes forever and does not run in background)
|
|
||||||
- currently loading in background thread produces segfaults in JNI
|
|
||||||
- check licenses of included libraries
|
|
||||||
|
|
||||||
### Issues
|
### Issues
|
||||||
- occasional crashes ...
|
- Pending incoming transactions disappear after reload (and appear after being mined)
|
||||||
|
|
||||||
### HOW TO BUILD
|
### HOW TO BUILD
|
||||||
No need to build. Binaries are included:
|
No need to build. Binaries are included:
|
||||||
|
|
||||||
- openssl-1.0.2l
|
- openssl-1.0.2l
|
||||||
- monero-v0.10.3.1 + pull requests #2238 & #2239
|
- monero-v0.10.3.1 + pull requests #2238, #2239 and #2289
|
||||||
- boost_1_64_0
|
- boost_1_64_0
|
||||||
|
|
||||||
If you want to build - fire up Android Studio and build. Also you can rebuild all of the above.
|
If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md)
|
||||||
|
|
||||||
|
Then, fire up Android Studio and build the APK.
|
||||||
|
|
||||||
|
### Donations
|
||||||
|
- Address: 4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk
|
||||||
|
- Viewkey: b1aff2a12191723da0afbe75516f94dd8b068215f6e847d8da57aca5f1f98e0c
|
3
app/.gitignore
vendored
Normal file
3
app/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.externalNativeBuild
|
||||||
|
build
|
||||||
|
app.iml
|
@@ -11,13 +11,13 @@ set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
|
|||||||
# OpenSSL
|
# OpenSSL
|
||||||
############
|
############
|
||||||
|
|
||||||
add_library(crypto SHARED IMPORTED)
|
add_library(crypto STATIC IMPORTED)
|
||||||
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
|
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.so)
|
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
|
||||||
|
|
||||||
add_library(ssl SHARED IMPORTED)
|
add_library(ssl STATIC IMPORTED)
|
||||||
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.so)
|
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
|
||||||
|
|
||||||
############
|
############
|
||||||
# Boost
|
# Boost
|
||||||
@@ -63,55 +63,55 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
|||||||
# Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct)
|
# Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct)
|
||||||
#############
|
#############
|
||||||
|
|
||||||
add_library(wallet SHARED IMPORTED)
|
add_library(wallet STATIC IMPORTED)
|
||||||
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
|
||||||
|
|
||||||
add_library(cryptonote_core SHARED IMPORTED)
|
add_library(cryptonote_core STATIC IMPORTED)
|
||||||
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
|
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.a)
|
||||||
|
|
||||||
add_library(cryptonote_basic SHARED IMPORTED)
|
add_library(cryptonote_basic STATIC IMPORTED)
|
||||||
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
|
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.a)
|
||||||
|
|
||||||
add_library(mnemonics SHARED IMPORTED)
|
add_library(mnemonics STATIC IMPORTED)
|
||||||
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
|
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.a)
|
||||||
|
|
||||||
add_library(common SHARED IMPORTED)
|
add_library(common STATIC IMPORTED)
|
||||||
set_target_properties(common PROPERTIES IMPORTED_LOCATION
|
set_target_properties(common PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.a)
|
||||||
|
|
||||||
add_library(cncrypto SHARED IMPORTED)
|
add_library(cncrypto STATIC IMPORTED)
|
||||||
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
|
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.a)
|
||||||
|
|
||||||
add_library(ringct SHARED IMPORTED)
|
add_library(ringct STATIC IMPORTED)
|
||||||
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
|
||||||
|
|
||||||
#####
|
#####
|
||||||
|
|
||||||
add_library(p2p SHARED IMPORTED)
|
add_library(p2p STATIC IMPORTED)
|
||||||
set_target_properties(p2p PROPERTIES IMPORTED_LOCATION
|
set_target_properties(p2p PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.a)
|
||||||
|
|
||||||
add_library(blockchain_db SHARED IMPORTED)
|
add_library(blockchain_db STATIC IMPORTED)
|
||||||
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.a)
|
||||||
|
|
||||||
add_library(lmdb SHARED IMPORTED)
|
add_library(lmdb STATIC IMPORTED)
|
||||||
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
|
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.a)
|
||||||
|
|
||||||
add_library(easylogging SHARED IMPORTED)
|
add_library(easylogging STATIC IMPORTED)
|
||||||
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.a)
|
||||||
|
|
||||||
add_library(unbound SHARED IMPORTED)
|
add_library(unbound STATIC IMPORTED)
|
||||||
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.so)
|
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
|
||||||
|
|
||||||
####
|
####
|
||||||
add_library(epee STATIC IMPORTED)
|
add_library(epee STATIC IMPORTED)
|
||||||
@@ -141,9 +141,10 @@ target_link_libraries( monerujo
|
|||||||
cryptonote_core
|
cryptonote_core
|
||||||
cryptonote_basic
|
cryptonote_basic
|
||||||
mnemonics
|
mnemonics
|
||||||
cncrypto
|
|
||||||
ringct
|
ringct
|
||||||
common
|
common
|
||||||
|
cncrypto
|
||||||
|
|
||||||
blockchain_db
|
blockchain_db
|
||||||
lmdb
|
lmdb
|
||||||
#easylogging # not for 0.10.3.1
|
#easylogging # not for 0.10.3.1
|
||||||
|
139
app/app.iml
139
app/app.iml
@@ -1,139 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="android-gradle" name="Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="native-android-gradle" name="Native-Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="android" name="Android">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
|
||||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
|
||||||
<afterSyncTasks>
|
|
||||||
<task>generateDebugSources</task>
|
|
||||||
</afterSyncTasks>
|
|
||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
|
||||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
|
||||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
|
||||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
|
||||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/cpp" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/cmake" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="runner-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-idling-resource-2.2.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="constraint-layout-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-library-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="transition-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-integration-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="design-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="cardview-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="jsr305-2.0.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-core-utils-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-fragment-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-core-2.2.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="exposed-instrumentation-api-publish-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="rules-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="constraint-layout-solver-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javax.annotation-api-1.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javax.inject-1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javawriter-2.1.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-v4-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-media-compat-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="recyclerview-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-annotations-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="appcompat-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-vector-drawable-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-compat-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="animated-vector-drawable-25.3.1" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 1
|
versionCode 8
|
||||||
versionName "0.1"
|
versionName "0.5.1"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
@@ -46,5 +46,6 @@ dependencies {
|
|||||||
compile 'com.android.support:support-v4:25.3.1'
|
compile 'com.android.support:support-v4:25.3.1'
|
||||||
compile 'com.android.support:recyclerview-v7:25.3.1'
|
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||||
compile 'com.android.support:cardview-v7:25.3.1'
|
compile 'com.android.support:cardview-v7:25.3.1'
|
||||||
|
compile 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -17,17 +18,28 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".WalletActivity"
|
android:name=".WalletActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/wallet_activity_name"
|
android:label="@string/wallet_activity_name"
|
||||||
android:launchMode="singleTop"></activity>
|
android:launchMode="singleTask"
|
||||||
|
android:screenOrientation="portrait" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
android:label="@string/app_name">
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:screenOrientation="portrait">
|
||||||
<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" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".service.WalletService"
|
||||||
|
android:description="@string/service_description"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="Monero Wallet Service" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,18 @@
|
|||||||
//
|
/**
|
||||||
// Created by m2049r on 15.04.2017.
|
* Copyright (c) 2017 m2049r
|
||||||
//
|
* <p>
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef XMRWALLET_WALLET_LIB_H
|
#ifndef XMRWALLET_WALLET_LIB_H
|
||||||
#define XMRWALLET_WALLET_LIB_H
|
#define XMRWALLET_WALLET_LIB_H
|
||||||
|
381
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
381
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class GenerateReviewFragment extends Fragment {
|
||||||
|
static final String TAG = "GenerateReviewFragment";
|
||||||
|
static final public String VIEW_DETAILS = "details";
|
||||||
|
static final public String VIEW_ACCEPT = "accept";
|
||||||
|
static final public String VIEW_WALLET = "wallet";
|
||||||
|
|
||||||
|
ProgressBar pbProgress;
|
||||||
|
TextView tvWalletName;
|
||||||
|
TextView tvWalletPassword;
|
||||||
|
TextView tvWalletAddress;
|
||||||
|
TextView tvWalletMnemonic;
|
||||||
|
TextView tvWalletViewKey;
|
||||||
|
TextView tvWalletSpendKey;
|
||||||
|
Button bAccept;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.gen_review_fragment, container, false);
|
||||||
|
|
||||||
|
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||||
|
tvWalletName = (TextView) view.findViewById(R.id.tvWalletName);
|
||||||
|
tvWalletPassword = (TextView) view.findViewById(R.id.tvWalletPassword);
|
||||||
|
tvWalletAddress = (TextView) view.findViewById(R.id.tvWalletAddress);
|
||||||
|
tvWalletViewKey = (TextView) view.findViewById(R.id.tvWalletViewKey);
|
||||||
|
tvWalletSpendKey = (TextView) view.findViewById(R.id.tvWalletSpendKey);
|
||||||
|
tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
|
||||||
|
|
||||||
|
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||||
|
|
||||||
|
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||||
|
tvWalletMnemonic.setTextIsSelectable(testnet);
|
||||||
|
tvWalletSpendKey.setTextIsSelectable(testnet);
|
||||||
|
|
||||||
|
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
acceptWallet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showProgress();
|
||||||
|
|
||||||
|
Bundle b = getArguments();
|
||||||
|
String type = b.getString("type");
|
||||||
|
if (!type.equals(VIEW_WALLET)) {
|
||||||
|
String name = b.getString("name");
|
||||||
|
String password = b.getString("password");
|
||||||
|
tvWalletName.setText(new File(name).getName());
|
||||||
|
show(name, password, type);
|
||||||
|
} else {
|
||||||
|
show(walletCallback.getWallet(), null, type);
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acceptWallet() {
|
||||||
|
String name = tvWalletName.getText().toString();
|
||||||
|
String password = tvWalletPassword.getText().toString();
|
||||||
|
bAccept.setEnabled(false);
|
||||||
|
acceptCallback.onAccept(name, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show(final String walletPath, final String password, final String type) {
|
||||||
|
new Thread(null,
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
|
||||||
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
show(wallet, password, type);
|
||||||
|
wallet.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, "DetailsReview", MoneroHandlerThread.THREAD_STACK_SIZE).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show(final Wallet wallet, final String password, final String type) {
|
||||||
|
if (type.equals(GenerateReviewFragment.VIEW_ACCEPT)) {
|
||||||
|
tvWalletPassword.setText(password);
|
||||||
|
bAccept.setVisibility(View.VISIBLE);
|
||||||
|
bAccept.setEnabled(true);
|
||||||
|
}
|
||||||
|
tvWalletName.setText(wallet.getName());
|
||||||
|
tvWalletAddress.setText(wallet.getAddress());
|
||||||
|
tvWalletMnemonic.setText(wallet.getSeed());
|
||||||
|
tvWalletViewKey.setText(wallet.getSecretViewKey());
|
||||||
|
String spend = wallet.isWatchOnly() ? "" : "not available - use seed for recovery";
|
||||||
|
if (spend.length() > 0) { //TODO should be == 64, but spendkey is not in the API yet
|
||||||
|
tvWalletSpendKey.setText(spend);
|
||||||
|
} else {
|
||||||
|
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
|
||||||
|
}
|
||||||
|
hideProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateReviewFragment.Listener acceptCallback = null;
|
||||||
|
GenerateReviewFragment.ListenerWithWallet walletCallback = null;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onAccept(String name, String password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ListenerWithWallet {
|
||||||
|
Wallet getWallet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof GenerateReviewFragment.Listener) {
|
||||||
|
this.acceptCallback = (GenerateReviewFragment.Listener) context;
|
||||||
|
} else if (context instanceof GenerateReviewFragment.ListenerWithWallet) {
|
||||||
|
this.walletCallback = (GenerateReviewFragment.ListenerWithWallet) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showProgress() {
|
||||||
|
pbProgress.setIndeterminate(true);
|
||||||
|
pbProgress.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideProgress() {
|
||||||
|
pbProgress.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
439
app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
Normal file
439
app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
131
app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java
Normal file
131
app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 dm77, 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.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
|
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||||
|
|
||||||
|
public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler {
|
||||||
|
static final String TAG = "ScannerFragment";
|
||||||
|
|
||||||
|
Listener activityCallback;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onAddressScanned(String address, String paymentId);
|
||||||
|
|
||||||
|
boolean isPaymentIdValid(String paymentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZXingScannerView mScannerView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
Log.d(TAG, "onCreateView");
|
||||||
|
mScannerView = new ZXingScannerView(getActivity());
|
||||||
|
return mScannerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Log.d(TAG, "onResume");
|
||||||
|
mScannerView.setResultHandler(this);
|
||||||
|
mScannerView.startCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
static final String URI_PREFIX = "monero:";
|
||||||
|
static final String PAYMENTID_STRING = "?tx_payment_id=";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleResult(Result rawResult) {
|
||||||
|
Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText());
|
||||||
|
String text = rawResult.getText();
|
||||||
|
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
|
||||||
|
(text.startsWith(URI_PREFIX))) {
|
||||||
|
String address = null;
|
||||||
|
String paymentId = null;
|
||||||
|
String s = text.substring(URI_PREFIX.length());
|
||||||
|
if (s.length() == 95) {
|
||||||
|
address = s;
|
||||||
|
} else {
|
||||||
|
int i = s.indexOf(PAYMENTID_STRING);
|
||||||
|
if ((i == 95) && (s.length() == (95 + PAYMENTID_STRING.length() + 16))) {
|
||||||
|
address = s.substring(0, 95);
|
||||||
|
paymentId = s.substring(95 + PAYMENTID_STRING.length());
|
||||||
|
if (!activityCallback.isPaymentIdValid(paymentId)) {
|
||||||
|
address = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Helper.isAddressOk(address, WalletManager.getInstance().isTestNet())) {
|
||||||
|
activityCallback.onAddressScanned(address, paymentId);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_qr_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note from dm77:
|
||||||
|
// * Wait 2 seconds to resume the preview.
|
||||||
|
// * On older devices continuously stopping and resuming camera preview can result in freezing the app.
|
||||||
|
// * I don't know why this is the case but I don't have the time to figure out.
|
||||||
|
Handler handler = new Handler();
|
||||||
|
handler.postDelayed(new
|
||||||
|
|
||||||
|
Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mScannerView.resumeCameraPreview(ScannerFragment.this);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
Log.d(TAG, "onPause");
|
||||||
|
mScannerView.stopCamera();
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
Log.d(TAG, "attaching scan");
|
||||||
|
if (context instanceof Listener) {
|
||||||
|
this.activityCallback = (Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
444
app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Normal file
444
app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
266
app/src/main/java/com/m2049r/xmrwallet/TxFragment.java
Normal file
266
app/src/main/java/com/m2049r/xmrwallet/TxFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
274
app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
Normal file
274
app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.layout;
|
package com.m2049r.xmrwallet.layout;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -22,13 +38,14 @@ import java.util.List;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> {
|
public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> {
|
||||||
static final String TAG = "TransactionInfoAdapter";
|
private static final String TAG = "TransactionInfoAdapter";
|
||||||
|
|
||||||
static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
|
private final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||||
static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss");
|
|
||||||
|
|
||||||
static final int TX_RED = Color.rgb(255, 79, 65);
|
static final int TX_RED = Color.rgb(255, 79, 65);
|
||||||
static final int TX_GREEN = Color.rgb(54, 176, 91);
|
static final int TX_GREEN = Color.rgb(54, 176, 91);
|
||||||
|
static final int TX_PENDING = Color.rgb(72, 53, 176);
|
||||||
|
static final int TX_FAILED = Color.rgb(208, 0, 255);
|
||||||
|
|
||||||
public interface OnInteractionListener {
|
public interface OnInteractionListener {
|
||||||
void onInteraction(View view, TransactionInfo item);
|
void onInteraction(View view, TransactionInfo item);
|
||||||
@@ -42,8 +59,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
TimeZone tz = cal.getTimeZone(); //get the local time zone.
|
TimeZone tz = cal.getTimeZone(); //get the local time zone.
|
||||||
DATE_FORMATTER.setTimeZone(tz);
|
DATETIME_FORMATTER.setTimeZone(tz);
|
||||||
TIME_FORMATTER.setTimeZone(tz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,6 +81,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
|
|
||||||
public void setInfos(List<TransactionInfo> data) {
|
public void setInfos(List<TransactionInfo> data) {
|
||||||
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
||||||
|
// as the TransactionInfo items are always recreated, we cannot recycle
|
||||||
this.infoItems.clear();
|
this.infoItems.clear();
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
Log.d(TAG, "setInfos " + data.size());
|
Log.d(TAG, "setInfos " + data.size());
|
||||||
@@ -72,9 +89,15 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
Collections.sort(data, new Comparator<TransactionInfo>() {
|
Collections.sort(data, new Comparator<TransactionInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(TransactionInfo o1, TransactionInfo o2) {
|
public int compare(TransactionInfo o1, TransactionInfo o2) {
|
||||||
long b1 = o1.getBlockHeight();
|
long b1 = o1.timestamp;
|
||||||
long b2 = o2.getBlockHeight();
|
long b2 = o2.timestamp;
|
||||||
return (b1 > b2) ? -1 : (b1 < b2) ? 1 : 0;
|
if (b1 > b2) {
|
||||||
|
return -1;
|
||||||
|
} else if (b1 < b2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return o1.hash.compareTo(o2.hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.infoItems.addAll(data);
|
this.infoItems.addAll(data);
|
||||||
@@ -84,30 +107,26 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||||
public final TextView tvAmount;
|
final TextView tvAmount;
|
||||||
public final TextView tvAmountPoint;
|
final TextView tvAmountPoint;
|
||||||
public final TextView tvAmountDecimal;
|
final TextView tvAmountDecimal;
|
||||||
public final TextView tvDate;
|
final TextView tvPaymentId;
|
||||||
public final TextView tvTime;
|
final TextView tvDateTime;
|
||||||
public TransactionInfo infoItem;
|
TransactionInfo infoItem;
|
||||||
|
|
||||||
public ViewHolder(View itemView) {
|
ViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
|
this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
|
||||||
// I know this is stupid but can't be bothered to align decimals otherwise
|
// I know this is stupid but can't be bothered to align decimals otherwise
|
||||||
this.tvAmountPoint = (TextView) itemView.findViewById(R.id.tx_amount_point);
|
this.tvAmountPoint = (TextView) itemView.findViewById(R.id.tx_amount_point);
|
||||||
this.tvAmountDecimal = (TextView) itemView.findViewById(R.id.tx_amount_decimal);
|
this.tvAmountDecimal = (TextView) itemView.findViewById(R.id.tx_amount_decimal);
|
||||||
this.tvDate = (TextView) itemView.findViewById(R.id.tx_date);
|
this.tvPaymentId = (TextView) itemView.findViewById(R.id.tx_paymentid);
|
||||||
this.tvTime = (TextView) itemView.findViewById(R.id.tx_time);
|
this.tvDateTime = (TextView) itemView.findViewById(R.id.tx_datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDate(long time) {
|
private String getDateTime(long time) {
|
||||||
return DATE_FORMATTER.format(new Date(time * 1000));
|
return DATETIME_FORMATTER.format(new Date(time * 1000));
|
||||||
}
|
|
||||||
|
|
||||||
private String getTime(long time) {
|
|
||||||
return TIME_FORMATTER.format(new Date(time * 1000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTxColour(int clr) {
|
private void setTxColour(int clr) {
|
||||||
@@ -118,20 +137,29 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
|
|
||||||
void bind(int position) {
|
void bind(int position) {
|
||||||
this.infoItem = infoItems.get(position);
|
this.infoItem = infoItems.get(position);
|
||||||
String displayAmount = Wallet.getDisplayAmount(infoItem.getAmount());
|
String displayAmount = Wallet.getDisplayAmount(infoItem.amount);
|
||||||
// TODO fix this with i8n code
|
// TODO fix this with i8n code but cryptonote::print_money always uses '.' for decimal point
|
||||||
String amountParts[] = displayAmount.split("\\.");
|
String amountParts[] = displayAmount.split("\\.");
|
||||||
// TODO what if there is no decimal point?
|
amountParts[1] = amountParts[1].substring(0,5);
|
||||||
|
|
||||||
this.tvAmount.setText(amountParts[0]);
|
this.tvAmount.setText(amountParts[0]);
|
||||||
this.tvAmountDecimal.setText(amountParts[1]);
|
this.tvAmountDecimal.setText(amountParts[1]);
|
||||||
if (infoItem.getDirection() == TransactionInfo.Direction.Direction_In) {
|
if (infoItem.isFailed) {
|
||||||
|
this.tvAmount.setText('(' + amountParts[0]);
|
||||||
|
this.tvAmountDecimal.setText(amountParts[1] + ')');
|
||||||
|
setTxColour(TX_FAILED);
|
||||||
|
} else if (infoItem.isPending) {
|
||||||
|
setTxColour(TX_PENDING);
|
||||||
|
if (infoItem.direction == TransactionInfo.Direction.Direction_Out) {
|
||||||
|
this.tvAmount.setText('-' + amountParts[0]);
|
||||||
|
}
|
||||||
|
} else if (infoItem.direction == TransactionInfo.Direction.Direction_In) {
|
||||||
setTxColour(TX_GREEN);
|
setTxColour(TX_GREEN);
|
||||||
} else {
|
} else {
|
||||||
setTxColour(TX_RED);
|
setTxColour(TX_RED);
|
||||||
}
|
}
|
||||||
this.tvDate.setText(getDate(infoItem.getTimestamp()));
|
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000")?"":infoItem.paymentId);
|
||||||
this.tvTime.setText(getTime(infoItem.getTimestamp()));
|
this.tvDateTime.setText(getDateTime(infoItem.timestamp));
|
||||||
|
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
public class PendingTransaction {
|
||||||
|
static {
|
||||||
|
System.loadLibrary("monerujo");
|
||||||
|
}
|
||||||
|
|
||||||
|
public long handle;
|
||||||
|
|
||||||
|
PendingTransaction(long handle) {
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
Status_Ok,
|
||||||
|
Status_Error,
|
||||||
|
Status_Critical
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Priority {
|
||||||
|
Priority_Low(1),
|
||||||
|
Priority_Medium(2),
|
||||||
|
Priority_High(3),
|
||||||
|
Priority_Last(4);
|
||||||
|
|
||||||
|
public static Priority fromInteger(int n) {
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
return Priority_Low;
|
||||||
|
case 2:
|
||||||
|
return Priority_Medium;
|
||||||
|
case 3:
|
||||||
|
return Priority_High;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
Priority(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getStatus() {
|
||||||
|
return Status.values()[getStatusJ()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public native int getStatusJ();
|
||||||
|
|
||||||
|
public native String getErrorString();
|
||||||
|
|
||||||
|
// commit transaction or save to file if filename is provided.
|
||||||
|
public native boolean commit(String filename, boolean overwrite);
|
||||||
|
|
||||||
|
public native long getAmount();
|
||||||
|
|
||||||
|
public native long getDust();
|
||||||
|
|
||||||
|
public native long getFee();
|
||||||
|
|
||||||
|
public native String getFirstTxId();
|
||||||
|
|
||||||
|
public native long getTxCount();
|
||||||
|
|
||||||
|
}
|
@@ -1,5 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TransactionHistory {
|
public class TransactionHistory {
|
||||||
@@ -13,34 +30,22 @@ public class TransactionHistory {
|
|||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionInfo getTransaction(int i) {
|
|
||||||
long infoHandle = getTransactionByIndexJ(i);
|
|
||||||
return new TransactionInfo(infoHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransactionInfo getTransaction(String id) {
|
|
||||||
long infoHandle = getTransactionByIdJ(id);
|
|
||||||
return new TransactionInfo(infoHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public List<TransactionInfo> getAll() {
|
|
||||||
List<Long> handles = getAllJ();
|
|
||||||
List<TransactionInfo> infoList = new ArrayList<TransactionInfo>();
|
|
||||||
for (Long handle : handles) {
|
|
||||||
infoList.add(new TransactionInfo(handle.longValue()));
|
|
||||||
}
|
|
||||||
return infoList;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public native int getCount();
|
public native int getCount();
|
||||||
|
|
||||||
private native long getTransactionByIndexJ(int i);
|
//private native long getTransactionByIndexJ(int i);
|
||||||
|
|
||||||
private native long getTransactionByIdJ(String id);
|
//private native long getTransactionByIdJ(String id);
|
||||||
|
|
||||||
public native List<TransactionInfo> getAll();
|
public List<TransactionInfo> getAll() {
|
||||||
|
return transactions;
|
||||||
|
}
|
||||||
|
|
||||||
public native void refresh();
|
private List<TransactionInfo> transactions = new ArrayList<>();
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
transactions = refreshJ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private native List<TransactionInfo> refreshJ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,78 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
public class TransactionInfo {
|
import android.os.Parcel;
|
||||||
static {
|
import android.os.Parcelable;
|
||||||
System.loadLibrary("monerujo");
|
import android.util.Log;
|
||||||
}
|
|
||||||
|
|
||||||
public long handle;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public TransactionInfo(long handle) {
|
// this is not the TransactionInfo from the API as that is owned by the TransactionHistory
|
||||||
this.handle = handle;
|
// this is a POJO for the TransactionInfoAdapter
|
||||||
}
|
public class TransactionInfo implements Parcelable {
|
||||||
|
static final String TAG = "TransactionInfo";
|
||||||
|
|
||||||
public enum Direction {
|
public enum Direction {
|
||||||
Direction_In,
|
Direction_In(0),
|
||||||
Direction_Out
|
Direction_Out(1);
|
||||||
}
|
|
||||||
|
|
||||||
public class Transfer {
|
public static Direction fromInteger(int n) {
|
||||||
long amount;
|
switch (n) {
|
||||||
String address;
|
case 0:
|
||||||
|
return Direction_In;
|
||||||
public Transfer(long amount, String address) {
|
case 1:
|
||||||
this.amount = amount;
|
return Direction_Out;
|
||||||
this.address = address;
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getAmount() {
|
public int getValue() {
|
||||||
return amount;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddress() {
|
private int value;
|
||||||
return address;
|
|
||||||
|
Direction(int value) {
|
||||||
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Direction direction;
|
||||||
|
public boolean isPending;
|
||||||
|
public boolean isFailed;
|
||||||
|
public long amount;
|
||||||
|
public long fee;
|
||||||
|
public long blockheight;
|
||||||
|
public String hash;
|
||||||
|
public long timestamp;
|
||||||
|
public String paymentId;
|
||||||
|
public long confirmations;
|
||||||
|
public List<Transfer> transfers;
|
||||||
|
|
||||||
|
public String txKey = null;
|
||||||
|
public String notes = null;
|
||||||
|
|
||||||
|
public TransactionInfo(
|
||||||
|
int direction,
|
||||||
|
boolean isPending,
|
||||||
|
boolean isFailed,
|
||||||
|
long amount,
|
||||||
|
long fee,
|
||||||
|
long blockheight,
|
||||||
|
String hash,
|
||||||
|
long timestamp,
|
||||||
|
String paymentId,
|
||||||
|
long confirmations,
|
||||||
|
List<Transfer> transfers) {
|
||||||
|
this.direction = Direction.values()[direction];
|
||||||
|
this.isPending = isPending;
|
||||||
|
this.isFailed = isFailed;
|
||||||
|
this.amount = amount;
|
||||||
|
this.fee = fee;
|
||||||
|
this.blockheight = blockheight;
|
||||||
|
this.hash = hash;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.paymentId = paymentId;
|
||||||
|
this.confirmations = confirmations;
|
||||||
|
this.transfers = transfers;
|
||||||
|
}
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getDirection() + "@" + getBlockHeight() + " " + getAmount();
|
return direction + "@" + blockheight + " " + amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getDirection() {
|
@Override
|
||||||
return TransactionInfo.Direction.values()[getDirectionJ()];
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeInt(direction.getValue());
|
||||||
|
out.writeByte((byte) (isPending ? 1 : 0));
|
||||||
|
out.writeByte((byte) (isFailed ? 1 : 0));
|
||||||
|
out.writeLong(amount);
|
||||||
|
out.writeLong(fee);
|
||||||
|
out.writeLong(blockheight);
|
||||||
|
out.writeString(hash);
|
||||||
|
out.writeLong(timestamp);
|
||||||
|
out.writeString(paymentId);
|
||||||
|
out.writeLong(confirmations);
|
||||||
|
out.writeList(transfers);
|
||||||
|
out.writeString(txKey);
|
||||||
|
out.writeString(notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public native int getDirectionJ();
|
public static final Parcelable.Creator<TransactionInfo> CREATOR = new Parcelable.Creator<TransactionInfo>() {
|
||||||
|
public TransactionInfo createFromParcel(Parcel in) {
|
||||||
public native boolean isPending();
|
return new TransactionInfo(in);
|
||||||
|
|
||||||
public native boolean isFailed();
|
|
||||||
|
|
||||||
public native long getAmount();
|
|
||||||
|
|
||||||
public native long getFee();
|
|
||||||
|
|
||||||
public native long getBlockHeight();
|
|
||||||
|
|
||||||
public native long getConfirmations();
|
|
||||||
|
|
||||||
public native String getHash();
|
|
||||||
|
|
||||||
public native long getTimestamp();
|
|
||||||
|
|
||||||
public native String getPaymentId();
|
|
||||||
|
|
||||||
/*
|
|
||||||
private List<Transfer> transfers;
|
|
||||||
|
|
||||||
public List<Transfer> getTransfers() { // not threadsafe
|
|
||||||
if (this.transfers == null) {
|
|
||||||
this.transfers = getTransfersJ();
|
|
||||||
}
|
}
|
||||||
return this.transfers;
|
|
||||||
|
public TransactionInfo[] newArray(int size) {
|
||||||
|
return new TransactionInfo[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private TransactionInfo(Parcel in) {
|
||||||
|
direction = Direction.fromInteger(in.readInt());
|
||||||
|
isPending = in.readByte() != 0;
|
||||||
|
isFailed = in.readByte() != 0;
|
||||||
|
amount = in.readLong();
|
||||||
|
fee = in.readLong();
|
||||||
|
blockheight = in.readLong();
|
||||||
|
hash = in.readString();
|
||||||
|
timestamp = in.readLong();
|
||||||
|
paymentId = in.readString();
|
||||||
|
confirmations = in.readLong();
|
||||||
|
transfers = in.readArrayList(Transfer.class.getClassLoader());
|
||||||
|
txKey = in.readString();
|
||||||
|
notes = in.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private native List<Transfer> getTransfersJ();
|
@Override
|
||||||
*/
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
59
app/src/main/java/com/m2049r/xmrwallet/model/Transfer.java
Normal file
59
app/src/main/java/com/m2049r/xmrwallet/model/Transfer.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.util.TxData;
|
||||||
|
|
||||||
|
public class Transfer implements Parcelable {
|
||||||
|
public long amount;
|
||||||
|
public String address;
|
||||||
|
|
||||||
|
public Transfer(long amount, String address) {
|
||||||
|
this.amount = amount;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeLong(amount);
|
||||||
|
out.writeString(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Transfer> CREATOR = new Parcelable.Creator<Transfer>() {
|
||||||
|
public Transfer createFromParcel(Parcel in) {
|
||||||
|
return new Transfer(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transfer[] newArray(int size) {
|
||||||
|
return new Transfer[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Transfer(Parcel in) {
|
||||||
|
amount = in.readLong();
|
||||||
|
address = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,7 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
public class Wallet {
|
public class Wallet {
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("monerujo");
|
System.loadLibrary("monerujo");
|
||||||
@@ -9,10 +27,14 @@ public class Wallet {
|
|||||||
|
|
||||||
static final String TAG = "Wallet";
|
static final String TAG = "Wallet";
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return new File(getPath()).getName();
|
||||||
|
}
|
||||||
|
|
||||||
private long handle = 0;
|
private long handle = 0;
|
||||||
private long listenerHandle = 0;
|
private long listenerHandle = 0;
|
||||||
|
|
||||||
public Wallet(long handle) {
|
Wallet(long handle) {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,8 +52,6 @@ public class Wallet {
|
|||||||
|
|
||||||
//public native long createWalletListenerJ();
|
//public native long createWalletListenerJ();
|
||||||
|
|
||||||
public native boolean close(); // from WalletManager
|
|
||||||
|
|
||||||
public native String getSeed();
|
public native String getSeed();
|
||||||
|
|
||||||
public native String getSeedLanguage();
|
public native String getSeedLanguage();
|
||||||
@@ -62,15 +82,28 @@ public class Wallet {
|
|||||||
public native String getSecretViewKey();
|
public native String getSecretViewKey();
|
||||||
|
|
||||||
public boolean store() {
|
public boolean store() {
|
||||||
return store(this.getPath());
|
return store("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public native boolean store(String path);
|
public native boolean store(String path);
|
||||||
|
|
||||||
|
public boolean close() {
|
||||||
|
disposePendingTransaction();
|
||||||
|
return WalletManager.getInstance().close(this);
|
||||||
|
}
|
||||||
|
|
||||||
public native String getFilename();
|
public native String getFilename();
|
||||||
|
|
||||||
// virtual std::string keysFilename() const = 0;
|
// virtual std::string keysFilename() const = 0;
|
||||||
public native boolean init(String daemon_address, long upper_transaction_size_limit);
|
public boolean init(long upper_transaction_size_limit) {
|
||||||
|
return initJ(WalletManager.getInstance().getDaemonAddress(), upper_transaction_size_limit,
|
||||||
|
WalletManager.getInstance().getDaemonUsername(),
|
||||||
|
WalletManager.getInstance().getDaemonPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
private native boolean initJ(String daemon_address, long upper_transaction_size_limit,
|
||||||
|
String daemon_username, String daemon_password);
|
||||||
|
|
||||||
// virtual bool createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const = 0;
|
// virtual bool createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const = 0;
|
||||||
// virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0;
|
// virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0;
|
||||||
// virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0;
|
// virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0;
|
||||||
@@ -132,15 +165,48 @@ public class Wallet {
|
|||||||
//TODO virtual int autoRefreshInterval() const = 0;
|
//TODO virtual int autoRefreshInterval() const = 0;
|
||||||
|
|
||||||
|
|
||||||
//virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
private PendingTransaction pendingTransaction = null;
|
||||||
// optional<uint64_t> tvAmount, uint32_t mixin_count,
|
|
||||||
// PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
|
|
||||||
|
|
||||||
//virtual PendingTransaction * createSweepUnmixableTransaction() = 0;
|
public PendingTransaction getPendingTransaction() {
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disposePendingTransaction() {
|
||||||
|
if (pendingTransaction != null) {
|
||||||
|
disposeTransaction(pendingTransaction);
|
||||||
|
pendingTransaction = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingTransaction createTransaction(String dst_addr, String payment_id,
|
||||||
|
long amount, int mixin_count,
|
||||||
|
PendingTransaction.Priority priority) {
|
||||||
|
disposePendingTransaction();
|
||||||
|
int _priority = priority.getValue();
|
||||||
|
long txHandle = createTransactionJ(dst_addr, payment_id, amount, mixin_count, _priority);
|
||||||
|
pendingTransaction = new PendingTransaction(txHandle);
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private native long createTransactionJ(String dst_addr, String payment_id,
|
||||||
|
long amount, int mixin_count,
|
||||||
|
int priority);
|
||||||
|
|
||||||
|
|
||||||
|
public PendingTransaction createSweepUnmixableTransaction() {
|
||||||
|
disposePendingTransaction();
|
||||||
|
long txHandle = createSweepUnmixableTransactionJ();
|
||||||
|
pendingTransaction = new PendingTransaction(txHandle);
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private native long createSweepUnmixableTransactionJ();
|
||||||
|
|
||||||
//virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;
|
//virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;
|
||||||
//virtual bool submitTransaction(const std::string &fileName) = 0;
|
//virtual bool submitTransaction(const std::string &fileName) = 0;
|
||||||
//virtual void disposeTransaction(PendingTransaction * t) = 0;
|
|
||||||
|
public native void disposeTransaction(PendingTransaction pendingTransaction);
|
||||||
|
|
||||||
//virtual bool exportKeyImages(const std::string &filename) = 0;
|
//virtual bool exportKeyImages(const std::string &filename) = 0;
|
||||||
//virtual bool importKeyImages(const std::string &filename) = 0;
|
//virtual bool importKeyImages(const std::string &filename) = 0;
|
||||||
|
|
||||||
@@ -171,9 +237,10 @@ public class Wallet {
|
|||||||
|
|
||||||
public native void setDefaultMixin(int mixin);
|
public native void setDefaultMixin(int mixin);
|
||||||
|
|
||||||
//virtual bool setUserNote(const std::string &txid, const std::string ¬e) = 0;
|
public native boolean setUserNote(String txid, String note);
|
||||||
//virtual std::string getUserNote(const std::string &txid) const = 0;
|
public native String getUserNote(String txid);
|
||||||
//virtual std::string getTxKey(const std::string &txid) const = 0;
|
|
||||||
|
public native String getTxKey(String txid);
|
||||||
|
|
||||||
//virtual std::string signMessage(const std::string &message) = 0;
|
//virtual std::string signMessage(const std::string &message) = 0;
|
||||||
//virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
|
//virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
|
||||||
|
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
public interface WalletListener {
|
public interface WalletListener {
|
||||||
|
@@ -1,3 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -8,10 +24,12 @@ import java.io.FileReader;
|
|||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class WalletManager {
|
public class WalletManager {
|
||||||
final static String TAG = "WalletManager";
|
private final static String TAG = "WalletManager";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("monerujo");
|
System.loadLibrary("monerujo");
|
||||||
@@ -20,38 +38,81 @@ public class WalletManager {
|
|||||||
// no need to keep a reference to the REAL WalletManager (we get it every tvTime we need it)
|
// no need to keep a reference to the REAL WalletManager (we get it every tvTime we need it)
|
||||||
private static WalletManager Instance = null;
|
private static WalletManager Instance = null;
|
||||||
|
|
||||||
public static WalletManager getInstance() { // TODO not threadsafe
|
public static synchronized WalletManager getInstance() {
|
||||||
if (WalletManager.Instance == null) {
|
if (WalletManager.Instance == null) {
|
||||||
WalletManager.Instance = new WalletManager();
|
WalletManager.Instance = new WalletManager();
|
||||||
}
|
}
|
||||||
return WalletManager.Instance;
|
return WalletManager.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet createWallet(String path, String password, String language, boolean isTestNet) {
|
private WalletManager() {
|
||||||
long walletHandle = createWalletJ(path, password, language, isTestNet);
|
this.managedWallets = new HashMap<>();
|
||||||
return new Wallet(walletHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet openWallet(String path, String password, boolean isTestNet) {
|
private Map<String, Wallet> managedWallets;
|
||||||
long walletHandle = openWalletJ(path, password, isTestNet);
|
|
||||||
return new Wallet(walletHandle);
|
public Wallet getWallet(String walletId) {
|
||||||
|
return managedWallets.get(walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet recoveryWallet(String path, String mnemonic, boolean isTestNet) {
|
private void manageWallet(String walletId, Wallet wallet) {
|
||||||
return recoveryWallet(path, mnemonic, isTestNet, 0);
|
if (getWallet(walletId) != null) {
|
||||||
|
throw new IllegalStateException(walletId + " already under management!");
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Managing " + walletId);
|
||||||
|
managedWallets.put(walletId, wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet recoveryWallet(String path, String mnemonic, boolean isTestNet, long restoreHeight) {
|
private void unmanageWallet(String walletId) {
|
||||||
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet, restoreHeight);
|
if (getWallet(walletId) == null) {
|
||||||
return new Wallet(walletHandle);
|
throw new IllegalStateException(walletId + " not under management!");
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Unmanaging " + walletId);
|
||||||
|
managedWallets.remove(walletId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Wallet createWallet(String path, String password, String language) {
|
||||||
|
long walletHandle = createWalletJ(path, password, language, isTestNet());
|
||||||
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
|
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
|
||||||
|
|
||||||
|
public Wallet openWallet(String path, String password) {
|
||||||
|
long walletHandle = openWalletJ(path, password, isTestNet());
|
||||||
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
private native long openWalletJ(String path, String password, boolean isTestNet);
|
private native long openWalletJ(String path, String password, boolean isTestNet);
|
||||||
|
|
||||||
|
public Wallet recoveryWallet(String path, String mnemonic) {
|
||||||
|
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Wallet recoveryWallet(String path, String mnemonic, long restoreHeight) {
|
||||||
|
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet(), restoreHeight);
|
||||||
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
||||||
|
|
||||||
|
public Wallet createWalletFromKeys(String path, String language, long restoreHeight,
|
||||||
|
String addressString, String viewKeyString, String spendKeyString) {
|
||||||
|
long walletHandle = createWalletFromKeysJ(path, language, isTestNet(), restoreHeight,
|
||||||
|
addressString, viewKeyString, spendKeyString);
|
||||||
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
private native long createWalletFromKeysJ(String path, String language,
|
private native long createWalletFromKeysJ(String path, String language,
|
||||||
boolean isTestNet,
|
boolean isTestNet,
|
||||||
long restoreHeight,
|
long restoreHeight,
|
||||||
@@ -59,6 +120,20 @@ public class WalletManager {
|
|||||||
String viewKeyString,
|
String viewKeyString,
|
||||||
String spendKeyString);
|
String spendKeyString);
|
||||||
|
|
||||||
|
public native boolean closeJ(Wallet wallet);
|
||||||
|
|
||||||
|
public boolean close(Wallet wallet) {
|
||||||
|
String walletId = new File(wallet.getFilename()).getName();
|
||||||
|
unmanageWallet(walletId);
|
||||||
|
boolean closed = closeJ(wallet);
|
||||||
|
if (!closed) {
|
||||||
|
// in case we could not close it
|
||||||
|
// we unmanage it
|
||||||
|
manageWallet(walletId, wallet);
|
||||||
|
}
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
public native boolean walletExists(String path);
|
public native boolean walletExists(String path);
|
||||||
|
|
||||||
public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
|
public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
|
||||||
@@ -85,7 +160,7 @@ public class WalletManager {
|
|||||||
String filename = found[i].getName();
|
String filename = found[i].getName();
|
||||||
info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1
|
info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1
|
||||||
File addressFile = new File(path, info.name + ".address.txt");
|
File addressFile = new File(path, info.name + ".address.txt");
|
||||||
Log.d(TAG, addressFile.getAbsolutePath());
|
//Log.d(TAG, addressFile.getAbsolutePath());
|
||||||
info.address = "??????";
|
info.address = "??????";
|
||||||
BufferedReader addressReader = null;
|
BufferedReader addressReader = null;
|
||||||
try {
|
try {
|
||||||
@@ -111,20 +186,49 @@ public class WalletManager {
|
|||||||
|
|
||||||
//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;
|
||||||
|
|
||||||
String daemonAddress = null;
|
private String daemonAddress = null;
|
||||||
|
private boolean testnet = true;
|
||||||
|
|
||||||
public void setDaemonAddress(String address) {
|
public boolean isTestNet() {
|
||||||
|
if (daemonAddress == null) {
|
||||||
|
// assume testnet not explicitly initialised
|
||||||
|
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
|
||||||
|
}
|
||||||
|
return testnet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDaemon(String address, boolean testnet, String username, String password) {
|
||||||
|
//Log.d(TAG, "SETDAEMON " + username + "/" + password + "/" + address);
|
||||||
this.daemonAddress = address;
|
this.daemonAddress = address;
|
||||||
|
this.testnet = testnet;
|
||||||
|
this.daemonUsername = username;
|
||||||
|
this.daemonPassword = password;
|
||||||
setDaemonAddressJ(address);
|
setDaemonAddressJ(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDaemonAddress() {
|
public String getDaemonAddress() {
|
||||||
|
if (daemonAddress == null) {
|
||||||
|
// assume testnet not explicitly initialised
|
||||||
|
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
|
||||||
|
}
|
||||||
return this.daemonAddress;
|
return this.daemonAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native void setDaemonAddressJ(String address);
|
private native void setDaemonAddressJ(String address);
|
||||||
|
|
||||||
public native int getConnectedDaemonVersion();
|
String daemonUsername = "";
|
||||||
|
|
||||||
|
public String getDaemonUsername() {
|
||||||
|
return daemonUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
String daemonPassword = "";
|
||||||
|
|
||||||
|
public String getDaemonPassword() {
|
||||||
|
return daemonPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public native int getDaemonVersion();
|
||||||
|
|
||||||
public native long getBlockchainHeight();
|
public native long getBlockchainHeight();
|
||||||
|
|
||||||
|
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006 The Android Open Source Project
|
||||||
|
* 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.service;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Process;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handy class for starting a new thread that has a looper. The looper can then be
|
||||||
|
* used to create handler classes. Note that start() must still be called.
|
||||||
|
* The started Thread has a stck size of STACK_SIZE (=5MB)
|
||||||
|
*/
|
||||||
|
public class MoneroHandlerThread extends Thread {
|
||||||
|
// from src/cryptonote_config.h
|
||||||
|
static public final long THREAD_STACK_SIZE = 5 * 1024 * 1024;
|
||||||
|
int mPriority;
|
||||||
|
int mTid = -1;
|
||||||
|
Looper mLooper;
|
||||||
|
|
||||||
|
public MoneroHandlerThread(String name) {
|
||||||
|
super(null, null, name, THREAD_STACK_SIZE);
|
||||||
|
mPriority = Process.THREAD_PRIORITY_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a MoneroHandlerThread.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param priority The priority to run the thread at. The value supplied must be from
|
||||||
|
* {@link android.os.Process} and not from java.lang.Thread.
|
||||||
|
*/
|
||||||
|
public MoneroHandlerThread(String name, int priority) {
|
||||||
|
super(null, null, name, THREAD_STACK_SIZE);
|
||||||
|
mPriority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call back method that can be explicitly overridden if needed to execute some
|
||||||
|
* setup before Looper loops.
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected void onLooperPrepared() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mTid = Process.myTid();
|
||||||
|
Looper.prepare();
|
||||||
|
synchronized (this) {
|
||||||
|
mLooper = Looper.myLooper();
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
Process.setThreadPriority(mPriority);
|
||||||
|
onLooperPrepared();
|
||||||
|
Looper.loop();
|
||||||
|
mTid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the Looper associated with this thread. If this thread not been started
|
||||||
|
* or for any reason is isAlive() returns false, this method will return null. If this thread
|
||||||
|
* has been started, this method will block until the looper has been initialized.
|
||||||
|
*
|
||||||
|
* @return The looper.
|
||||||
|
*/
|
||||||
|
public Looper getLooper() {
|
||||||
|
if (!isAlive()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the thread has been started, wait until the looper has been created.
|
||||||
|
synchronized (this) {
|
||||||
|
while (isAlive() && mLooper == null) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mLooper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quits the handler thread's looper.
|
||||||
|
* <p>
|
||||||
|
* Causes the handler thread's looper to terminate without processing any
|
||||||
|
* more messages in the message queue.
|
||||||
|
* </p><p>
|
||||||
|
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
|
||||||
|
* For example, the {@link Handler#sendMessage(Message)} method will return false.
|
||||||
|
* </p><p class="note">
|
||||||
|
* Using this method may be unsafe because some messages may not be delivered
|
||||||
|
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
|
||||||
|
* that all pending work is completed in an orderly manner.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return True if the looper looper has been asked to quit or false if the
|
||||||
|
* thread had not yet started running.
|
||||||
|
* @see #quitSafely
|
||||||
|
*/
|
||||||
|
public boolean quit() {
|
||||||
|
Looper looper = getLooper();
|
||||||
|
if (looper != null) {
|
||||||
|
looper.quit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quits the handler thread's looper safely.
|
||||||
|
* <p>
|
||||||
|
* Causes the handler thread's looper to terminate as soon as all remaining messages
|
||||||
|
* in the message queue that are already due to be delivered have been handled.
|
||||||
|
* Pending delayed messages with due times in the future will not be delivered.
|
||||||
|
* </p><p>
|
||||||
|
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
|
||||||
|
* For example, the {@link Handler#sendMessage(Message)} method will return false.
|
||||||
|
* </p><p>
|
||||||
|
* If the thread has not been started or has finished (that is if
|
||||||
|
* {@link #getLooper} returns null), then false is returned.
|
||||||
|
* Otherwise the looper is asked to quit and true is returned.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return True if the looper looper has been asked to quit or false if the
|
||||||
|
* thread had not yet started running.
|
||||||
|
*/
|
||||||
|
public boolean quitSafely() {
|
||||||
|
Looper looper = getLooper();
|
||||||
|
if (looper != null) {
|
||||||
|
looper.quitSafely();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier of this thread. See Process.myTid().
|
||||||
|
*/
|
||||||
|
public int getThreadId() {
|
||||||
|
return mTid;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user