1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-03 08:23:04 +02:00

Compare commits

...

84 Commits

Author SHA1 Message Date
m2049r
5b38cc438c Merge pull request #27 from m2049r/docs
update docs and version
2017-08-30 22:24:49 +02:00
m2049r
1eac363102 update docs and version 2017-08-30 22:24:24 +02:00
m2049r
e51425bc2e Merge pull request #26 from m2049r/feature_qr
QR Scanning incl. payment id
2017-08-30 22:02:34 +02:00
m2049r
f5535dbefa QR Scanning incl. payment id 2017-08-30 21:36:07 +02:00
m2049r
2d42a0287d Merge pull request #25 from m2049r/docs
updated version number + docs
2017-08-29 23:41:38 +02:00
m2049r
2ebb9d0650 updated version number + docs 2017-08-29 23:40:46 +02:00
m2049r
30792c53c0 Merge pull request #24 from m2049r/feature_spend_mainnet
mainnet spending
2017-08-29 22:37:23 +02:00
m2049r
3846a0c391 mainnet spending 2017-08-29 22:22:07 +02:00
m2049r
c66ebd654a Merge pull request #23 from m2049r/cleanup
Lots of GUI tweaks
2017-08-29 22:07:17 +02:00
m2049r
186ed5cd39 second spend confirmation for mainnet 2017-08-29 22:05:51 +02:00
m2049r
e39cd1c988 lots of GUI tweaks 2017-08-29 22:05:45 +02:00
m2049r
39d9c4d0c3 Merge pull request #22 from m2049r/feature_colours
balance colour + tx ordering
2017-08-29 08:44:36 +02:00
m2049r
e4562f07a4 balance colour + tx ordering 2017-08-29 08:43:56 +02:00
m2049r
b3ea4540a1 Merge pull request #21 from m2049r/feature_toolbar
Toolbars + action & context menu
2017-08-28 23:51:36 +02:00
m2049r
ea7c7d2fdb net colour in toolbar 2017-08-28 23:46:18 +02:00
m2049r
8ff8be6f60 list context menu + tweaks 2017-08-28 23:14:53 +02:00
m2049r
b5ded700fe toolbar info action for wallet activity 2017-08-28 22:10:17 +02:00
m2049r
a5527d4efd use default daemon ports if none supplied 2017-08-28 19:38:13 +02:00
m2049r
a007810824 Merge pull request #20 from m2049r/feature_list_addfab
nicer add icon
2017-08-27 22:58:36 +02:00
m2049r
a634cf18b1 nicer fab icon 2017-08-27 22:57:35 +02:00
m2049r
0b2fa08df8 Merge pull request #19 from m2049r/feature_list_addfab
Create wallet by action button
2017-08-27 09:14:52 +02:00
m2049r
191aa6ac22 action button for create wallet + setting activity title in LoginActivity 2017-08-27 09:12:53 +02:00
m2049r
a82a90575d deamon prompt show syntax 2017-08-26 00:34:17 +02:00
m2049r
2e04046f50 Merge pull request #18 from m2049r/feature_layout
simple layout
2017-08-26 00:29:41 +02:00
m2049r
c11d577c5f simple layout
minimum number of decimal places
progress at top
2017-08-26 00:27:27 +02:00
m2049r
74b2dd209c Merge pull request #17 from m2049r/feature_daemon_userpassword
Username/Password for daemon
2017-08-24 00:06:18 +02:00
m2049r
cb1d541474 Username/Password for daemon 2017-08-24 00:03:23 +02:00
m2049r
807d217aac Merge pull request #16 from m2049r/feature_txrecipient
show destinations in tx view
2017-08-22 13:10:14 +02:00
m2049r
0421bcfac3 show destination in tx view 2017-08-22 13:02:31 +02:00
m2049r
b6c4e06fda Merge pull request #15 from m2049r/feature_spend_redo
enable dispose of prepared transaction
2017-08-22 11:10:19 +02:00
m2049r
3ee8343074 enable dispose of prepared transaction 2017-08-22 11:05:43 +02:00
m2049r
110621824a Merge pull request #14 from m2049r/hotfix_priority
passing of transaction priority fixed
2017-08-22 10:56:07 +02:00
m2049r
7194580fbe passing of transaction priority fixed 2017-08-22 10:54:16 +02:00
m2049r
48dcd37740 Update build.gradle 2017-08-22 00:19:53 +02:00
m2049r
8e619756b9 Merge pull request #13 from m2049r/feature_service_notification
start WalletService as foreground service
2017-08-21 17:33:08 +02:00
m2049r
6c6b47db7d Merge pull request #12 from m2049r/bugfix
don't show Send Button on mainnet (instead of crashing when clicked)
2017-08-21 17:31:45 +02:00
m2049r
a126844272 start WalletService as foreground service preventing it from being killed by the system 2017-08-21 15:58:22 +02:00
m2049r
9b3086ff2e don't show Send Button on mainnet (instead of crashing when clicked) 2017-08-21 10:14:19 +02:00
m2049r
89d1842d59 Update README.md 2017-08-21 00:22:57 +02:00
m2049r
d44067e952 Merge pull request #11 from m2049r/feature_send
doc
2017-08-20 22:47:20 +02:00
m2049r
0370eaa619 doc 2017-08-20 22:45:46 +02:00
m2049r
35c393495a Merge pull request #10 from m2049r/feature_send
Sending
2017-08-20 22:42:22 +02:00
m2049r
f19618e017 docs 2017-08-20 22:35:42 +02:00
m2049r
3a68802ae7 deal with pending transactions 2017-08-20 22:35:31 +02:00
m2049r
344eeb7a3b removed debugging code + docs + some bugfixing 2017-08-20 22:35:03 +02:00
m2049r
4ad58684b4 failsafe sending in mainnet
- die ungracefully with an exception because this should be possible anyway
2017-08-20 22:35:03 +02:00
m2049r
30e35a895d cleanup + docs 2017-08-20 22:34:36 +02:00
m2049r
37414be4bf tx notes added + tx details + tweaks 2017-08-20 16:24:35 +02:00
m2049r
a37ca4c0e5 tweaks + sweep 2017-08-19 18:59:38 +02:00
m2049r
408b1a68d0 tx key + tweaks 2017-08-19 16:20:10 +02:00
m2049r
40da44222e sending done + added Transfers + tweaks 2017-08-19 13:44:04 +02:00
m2049r
b0efdca928 send gui + first successful send transaction! 2017-08-19 13:43:29 +02:00
m2049r
d61198b47f Merge pull request #9 from m2049r/feature_walletinfo
Wallet Details on long press in wallet list
2017-08-18 09:35:02 +02:00
m2049r
62433f6e10 tweaks & fixed store() error, refactoring 2017-08-18 02:46:56 +02:00
m2049r
c9ae39508f details view works mostly (seed)
need to prevent opening wallet while preparing details
new wallets sont store the cache ?! (except watch only)
2017-08-18 00:18:57 +02:00
m2049r
44836a24bb tweaks 2017-08-18 00:18:43 +02:00
m2049r
80e60bd0c8 Merge pull request #8 from m2049r/feature_gen
Wallet Creation & Recovery
2017-08-17 14:17:13 +02:00
m2049r
9f38b957e1 lots of minor fixes & tweaks. do not copy cache.
the cache file is corrupt after recovery (except watch only).
2017-08-17 14:13:26 +02:00
m2049r
032aa24ab5 cleanup & AppCompatActivity & setTitle 2017-08-16 22:22:41 +02:00
m2049r
afc45e1cbc UI tweaks 2017-08-16 21:28:00 +02:00
m2049r
bd598deddd separate wallet generation & confirmation
all methods of recovery & creation implemented
2017-08-16 21:28:00 +02:00
m2049r
952fb3a7f1 deal with user closing fragment while doing wallet stuff 2017-08-16 21:28:00 +02:00
m2049r
fb62074d20 added app.iml to gitignore and updates android studio 2017-08-16 21:27:36 +02:00
m2049r
56132e26ed tweaks - mostly keyboard & UI 2017-08-16 12:01:32 +02:00
m2049r
3239bdeb33 removed default localhost daemons 2017-08-16 00:49:48 +02:00
m2049r
142885821e Generate Wallet command added to wallet list 2017-08-16 00:28:53 +02:00
m2049r
34941c599a Generate Wallet Fragment added 2017-08-15 23:59:41 +02:00
m2049r
58c8f1896c Merge pull request #7 from m2049r/fragment
Fragmented Activites
2017-08-15 12:17:56 +02:00
m2049r
6611539491 some cleaning up 2017-08-15 12:13:58 +02:00
m2049r
69729e5257 LoginActivity now fragmented 2017-08-15 12:01:53 +02:00
m2049r
535158c5e9 refactored WalletActivity to use fragments 2017-08-15 09:43:19 +02:00
m2049r
61e2d880c2 Merge pull request #6 from m2049r/docs
updated docs
2017-08-14 10:48:38 +02:00
m2049r
72889fcdde Create BUILDING-external-libs.md
Update README.md
2017-08-14 10:47:04 +02:00
m2049r
905ee8b8a9 Merge pull request #5 from m2049r/features
allow only portrait
2017-08-14 10:02:50 +02:00
m2049r
81a9aa6938 allow only portrait
remove some debug messages
2017-08-14 10:01:22 +02:00
m2049r
046238a29f Merge pull request #4 from m2049r/features
lots of tweaks
2017-08-14 09:30:16 +02:00
m2049r
9751825ed7 stack size for background thread set to 5MB (monero dafault)
so no need to use heap for slow_hash
recompiled monero without USE_HEAP
2017-08-14 09:26:59 +02:00
m2049r
c19ee65dd1 UI & progress bar tweaks
service start/stop in activity onCreate/onDestroy
update continues in background if screen turned off
2017-08-13 15:39:11 +02:00
m2049r
282f00959d reverted libwallet crypto CMake 2017-08-13 00:29:58 +02:00
m2049r
104a6063a3 Merge pull request #3 from m2049r/features
check daemon availability & save only on first sync
2017-08-12 19:59:45 +02:00
m2049r
95e47e3407 check daemon availability
show txs immediately
only save on first sync

no store on close

Increased Version
2017-08-12 19:56:06 +02:00
m2049r
cb5795e64b remove .so 2017-08-07 08:58:13 +02:00
m2049r
746da913f0 Merge branch 'master' into feature_async 2017-08-07 08:56:22 +02:00
m2049r
2682399600 save prefs
async wallet load / close by service
wakelock & async loading / closing looks good
progress indicator
ode cleanup
added license boilerplates
2017-08-07 08:13:23 +02:00
122 changed files with 6221 additions and 4323 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.gradle
build

2
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
workspace.xml
markdown-navigator*

10
.idea/libraries/core_1_9_8.xml generated Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -3,49 +3,43 @@ Another Android Monero Wallet
### QUICKSTART
- Download APK (Release) and install it
- Copy over synced wallet (all three files) onto sdcard in directory Monerujo (created first time app is started)
- Start app (again)
- Run the App and select "Generate Wallet" to create a new wallet or recover a wallet
- 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)
### 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
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
- Special thanks to /u/gkruja for inspiration to pick this project up again
- Based off monero v0.10.3.1 with pull requests #2238 & #2239 applied => so can be used in mainnet!
- currently only android32
- 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)
### Random Notes
- Based off monero v0.10.3.1 with pull requests #2238, #2239 and #2289 applied => so can be used in mainnet!
- currently only android32 (runs on 64-bit as well)
- works in testnet & mainnet
- takes forever to sync due to 32-bit architecture
- use your own daemon - it's easy
- screen stays on until first sync is complete
- saves wallet only on first sync and when sending transactions or editing notes
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
### TODO
- don't have the screen on for first sync - use IntentService with WakeLock instead?
- make it pretty
- show current block height - is that relevant?
- 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
- wallet backup functions
- review visibility of methods/classes
- more sensible error dialogs
- check licenses of included libraries; License Dialog
### Issues
- occasional crashes ...
- Pending incoming transactions disappear after reload (and appear after being mined)
### HOW TO BUILD
No need to build. Binaries are included:
- 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
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
View File

@@ -0,0 +1,3 @@
.externalNativeBuild
build
app.iml

View File

@@ -11,13 +11,13 @@ set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
# OpenSSL
############
add_library(crypto SHARED IMPORTED)
add_library(crypto STATIC IMPORTED)
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
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.so)
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
############
# 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)
#############
add_library(wallet SHARED IMPORTED)
add_library(wallet STATIC IMPORTED)
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
${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
${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
${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
${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
${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
${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
${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
${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
${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
${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
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.so)
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
####
add_library(epee STATIC IMPORTED)
@@ -141,9 +141,10 @@ target_link_libraries( monerujo
cryptonote_core
cryptonote_basic
mnemonics
cncrypto
ringct
common
cncrypto
blockchain_db
lmdb
#easylogging # not for 0.10.3.1

View File

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

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 1
versionName "0.1"
versionCode 8
versionName "0.5.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -46,5 +46,6 @@ dependencies {
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:recyclerview-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'
}

View File

@@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.READ_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.CAMERA" />
<application
android:allowBackup="true"
@@ -17,17 +18,28 @@
<activity
android:name=".WalletActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/wallet_activity_name"
android:launchMode="singleTop"></activity>
android:launchMode="singleTask"
android:screenOrientation="portrait" />
<activity
android:name=".LoginActivity"
android:label="@string/app_name">
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".service.WalletService"
android:description="@string/service_description"
android:exported="false"
android:label="Monero Wallet Service" />
</application>
</manifest>

File diff suppressed because it is too large Load Diff

View File

@@ -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
#define XMRWALLET_WALLET_LIB_H

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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;
import android.graphics.Color;
@@ -22,13 +38,14 @@ import java.util.List;
import java.util.TimeZone;
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");
static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss");
private final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
static final int TX_RED = Color.rgb(255, 79, 65);
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 {
void onInteraction(View view, TransactionInfo item);
@@ -42,8 +59,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
this.listener = listener;
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone(); //get the local time zone.
DATE_FORMATTER.setTimeZone(tz);
TIME_FORMATTER.setTimeZone(tz);
DATETIME_FORMATTER.setTimeZone(tz);
}
@Override
@@ -65,6 +81,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
public void setInfos(List<TransactionInfo> data) {
// 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();
if (data != null) {
Log.d(TAG, "setInfos " + data.size());
@@ -72,9 +89,15 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
Collections.sort(data, new Comparator<TransactionInfo>() {
@Override
public int compare(TransactionInfo o1, TransactionInfo o2) {
long b1 = o1.getBlockHeight();
long b2 = o2.getBlockHeight();
return (b1 > b2) ? -1 : (b1 < b2) ? 1 : 0;
long b1 = o1.timestamp;
long b2 = o2.timestamp;
if (b1 > b2) {
return -1;
} else if (b1 < b2) {
return 1;
} else {
return o1.hash.compareTo(o2.hash);
}
}
});
this.infoItems.addAll(data);
@@ -84,30 +107,26 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView tvAmount;
public final TextView tvAmountPoint;
public final TextView tvAmountDecimal;
public final TextView tvDate;
public final TextView tvTime;
public TransactionInfo infoItem;
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final TextView tvAmount;
final TextView tvAmountPoint;
final TextView tvAmountDecimal;
final TextView tvPaymentId;
final TextView tvDateTime;
TransactionInfo infoItem;
public ViewHolder(View itemView) {
ViewHolder(View itemView) {
super(itemView);
this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
// 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.tvAmountDecimal = (TextView) itemView.findViewById(R.id.tx_amount_decimal);
this.tvDate = (TextView) itemView.findViewById(R.id.tx_date);
this.tvTime = (TextView) itemView.findViewById(R.id.tx_time);
this.tvPaymentId = (TextView) itemView.findViewById(R.id.tx_paymentid);
this.tvDateTime = (TextView) itemView.findViewById(R.id.tx_datetime);
}
private String getDate(long time) {
return DATE_FORMATTER.format(new Date(time * 1000));
}
private String getTime(long time) {
return TIME_FORMATTER.format(new Date(time * 1000));
private String getDateTime(long time) {
return DATETIME_FORMATTER.format(new Date(time * 1000));
}
private void setTxColour(int clr) {
@@ -118,20 +137,29 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
void bind(int position) {
this.infoItem = infoItems.get(position);
String displayAmount = Wallet.getDisplayAmount(infoItem.getAmount());
// TODO fix this with i8n code
String displayAmount = Wallet.getDisplayAmount(infoItem.amount);
// TODO fix this with i8n code but cryptonote::print_money always uses '.' for decimal point
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.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);
} else {
setTxColour(TX_RED);
}
this.tvDate.setText(getDate(infoItem.getTimestamp()));
this.tvTime.setText(getTime(infoItem.getTimestamp()));
this.tvPaymentId.setText(infoItem.paymentId.equals("0000000000000000")?"":infoItem.paymentId);
this.tvDateTime.setText(getDateTime(infoItem.timestamp));
itemView.setOnClickListener(this);
}

View File

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

View File

@@ -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;
import java.util.ArrayList;
import java.util.List;
public class TransactionHistory {
@@ -13,34 +30,22 @@ public class TransactionHistory {
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();
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();
}

View File

@@ -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;
public class TransactionInfo {
static {
System.loadLibrary("monerujo");
}
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
public long handle;
import java.util.List;
import java.util.Random;
public TransactionInfo(long handle) {
this.handle = handle;
}
// this is not the TransactionInfo from the API as that is owned by the TransactionHistory
// this is a POJO for the TransactionInfoAdapter
public class TransactionInfo implements Parcelable {
static final String TAG = "TransactionInfo";
public enum Direction {
Direction_In,
Direction_Out
}
Direction_In(0),
Direction_Out(1);
public class Transfer {
long amount;
String address;
public Transfer(long amount, String address) {
this.amount = amount;
this.address = address;
public static Direction fromInteger(int n) {
switch (n) {
case 0:
return Direction_In;
case 1:
return Direction_Out;
}
return null;
}
public long getAmount() {
return amount;
public int getValue() {
return value;
}
public String getAddress() {
return address;
private int value;
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() {
return getDirection() + "@" + getBlockHeight() + " " + getAmount();
return direction + "@" + blockheight + " " + amount;
}
public Direction getDirection() {
return TransactionInfo.Direction.values()[getDirectionJ()];
@Override
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 native boolean isPending();
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();
public static final Parcelable.Creator<TransactionInfo> CREATOR = new Parcelable.Creator<TransactionInfo>() {
public TransactionInfo createFromParcel(Parcel in) {
return new TransactionInfo(in);
}
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;
}
}

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

View File

@@ -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;
import android.util.Log;
import java.io.File;
public class Wallet {
static {
System.loadLibrary("monerujo");
@@ -9,10 +27,14 @@ public class Wallet {
static final String TAG = "Wallet";
public String getName() {
return new File(getPath()).getName();
}
private long handle = 0;
private long listenerHandle = 0;
public Wallet(long handle) {
Wallet(long handle) {
this.handle = handle;
}
@@ -30,8 +52,6 @@ public class Wallet {
//public native long createWalletListenerJ();
public native boolean close(); // from WalletManager
public native String getSeed();
public native String getSeedLanguage();
@@ -62,15 +82,28 @@ public class Wallet {
public native String getSecretViewKey();
public boolean store() {
return store(this.getPath());
return store("");
}
public native boolean store(String path);
public boolean close() {
disposePendingTransaction();
return WalletManager.getInstance().close(this);
}
public native String getFilename();
// 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 void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0;
// virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0;
@@ -132,15 +165,48 @@ public class Wallet {
//TODO virtual int autoRefreshInterval() const = 0;
//virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
// optional<uint64_t> tvAmount, uint32_t mixin_count,
// PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
private PendingTransaction pendingTransaction = null;
//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 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 importKeyImages(const std::string &filename) = 0;
@@ -171,9 +237,10 @@ public class Wallet {
public native void setDefaultMixin(int mixin);
//virtual bool setUserNote(const std::string &txid, const std::string &note) = 0;
//virtual std::string getUserNote(const std::string &txid) const = 0;
//virtual std::string getTxKey(const std::string &txid) const = 0;
public native boolean setUserNote(String txid, String note);
public native String getUserNote(String txid);
public native String getTxKey(String txid);
//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;

View File

@@ -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;
public interface WalletListener {

View File

@@ -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;
import android.util.Log;
@@ -8,10 +24,12 @@ import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WalletManager {
final static String TAG = "WalletManager";
private final static String TAG = "WalletManager";
static {
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)
private static WalletManager Instance = null;
public static WalletManager getInstance() { // TODO not threadsafe
public static synchronized WalletManager getInstance() {
if (WalletManager.Instance == null) {
WalletManager.Instance = new WalletManager();
}
return WalletManager.Instance;
}
public Wallet createWallet(String path, String password, String language, boolean isTestNet) {
long walletHandle = createWalletJ(path, password, language, isTestNet);
return new Wallet(walletHandle);
private WalletManager() {
this.managedWallets = new HashMap<>();
}
public Wallet openWallet(String path, String password, boolean isTestNet) {
long walletHandle = openWalletJ(path, password, isTestNet);
return new Wallet(walletHandle);
private Map<String, Wallet> managedWallets;
public Wallet getWallet(String walletId) {
return managedWallets.get(walletId);
}
public Wallet recoveryWallet(String path, String mnemonic, boolean isTestNet) {
return recoveryWallet(path, mnemonic, isTestNet, 0);
private void manageWallet(String walletId, Wallet wallet) {
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) {
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet, restoreHeight);
return new Wallet(walletHandle);
private void unmanageWallet(String walletId) {
if (getWallet(walletId) == null) {
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);
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);
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);
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,
boolean isTestNet,
long restoreHeight,
@@ -59,6 +120,20 @@ public class WalletManager {
String viewKeyString,
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 verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
@@ -85,7 +160,7 @@ public class WalletManager {
String filename = found[i].getName();
info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1
File addressFile = new File(path, info.name + ".address.txt");
Log.d(TAG, addressFile.getAbsolutePath());
//Log.d(TAG, addressFile.getAbsolutePath());
info.address = "??????";
BufferedReader addressReader = null;
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;
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.testnet = testnet;
this.daemonUsername = username;
this.daemonPassword = password;
setDaemonAddressJ(address);
}
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;
}
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();

View File

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