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

Compare commits

...

77 Commits
v0.2.0 ... v0.5

Author SHA1 Message Date
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
66 changed files with 5184 additions and 1196 deletions

1
.idea/.gitignore generated vendored
View File

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

View File

@@ -3,47 +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
- 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
- make it pretty
- adjust layout so we can use bigger font sizes
- provide detailed build instructions for third party binaries
- visibility of methods/classes
- 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
- License Dialog
- wallet backup functions
- review visibility of methods/classes
- more sensible error dialogs
- check licenses of included libraries; License Dialog
### Issues
- screen rotation crashes the app
- turning the display off/on during sync stops sync
- 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

1
app/.gitignore vendored
View File

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

View File

@@ -1,147 +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-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" />
<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/reload-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
<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 2
versionName "0.2.0"
versionCode 7
versionName "0.5"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {

View File

@@ -17,12 +17,16 @@
<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" />

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

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,12 +1,12 @@
/**
/*
* 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.
@@ -38,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);
@@ -58,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
@@ -81,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());
@@ -88,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);
@@ -100,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) {
@@ -134,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,12 +1,12 @@
/**
/*
* 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.
@@ -16,6 +16,7 @@
package com.m2049r.xmrwallet.model;
import java.util.ArrayList;
import java.util.List;
public class TransactionHistory {
@@ -29,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,12 +1,12 @@
/**
/*
* 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.
@@ -16,79 +16,134 @@
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,12 +1,12 @@
/**
/*
* 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.
@@ -28,14 +28,13 @@ public class Wallet {
static final String TAG = "Wallet";
public String getName() {
String p = getPath();
return new File(p).getName();
return new File(getPath()).getName();
}
private long handle = 0;
private long listenerHandle = 0;
public Wallet(long handle) {
Wallet(long handle) {
this.handle = handle;
}
@@ -83,12 +82,13 @@ 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);
}
@@ -96,10 +96,13 @@ public class Wallet {
// virtual std::string keysFilename() const = 0;
public boolean init(long upper_transaction_size_limit) {
return initJ(WalletManager.getInstance().getDaemonAddress(), 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);
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;
@@ -162,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;
@@ -201,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,12 +1,12 @@
/**
/*
* 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.

View File

@@ -1,12 +1,12 @@
/**
/*
* 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.
@@ -29,7 +29,7 @@ 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");
@@ -38,7 +38,7 @@ 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();
}
@@ -57,7 +57,7 @@ public class WalletManager {
private void manageWallet(String walletId, Wallet wallet) {
if (getWallet(walletId) != null) {
throw new IllegalStateException("Wallet already under management!");
throw new IllegalStateException(walletId + " already under management!");
}
Log.d(TAG, "Managing " + walletId);
managedWallets.put(walletId, wallet);
@@ -65,7 +65,7 @@ public class WalletManager {
private void unmanageWallet(String walletId) {
if (getWallet(walletId) == null) {
throw new IllegalStateException("Wallet not under management!");
throw new IllegalStateException(walletId + " not under management!");
}
Log.d(TAG, "Unmanaging " + walletId);
managedWallets.remove(walletId);
@@ -78,6 +78,8 @@ public class WalletManager {
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);
@@ -85,6 +87,8 @@ public class WalletManager {
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);
@@ -98,12 +102,17 @@ public class WalletManager {
return wallet;
}
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
private native long openWalletJ(String path, String password, boolean isTestNet);
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,
@@ -188,9 +197,12 @@ public class WalletManager {
return testnet;
}
public void setDaemon(String address, boolean 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);
}
@@ -204,7 +216,19 @@ public class WalletManager {
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;
}
}

View File

@@ -1,12 +1,12 @@
/**
/*
* 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.
@@ -18,18 +18,21 @@ package com.m2049r.xmrwallet.util;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.util.Log;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import com.m2049r.xmrwallet.R;
import java.io.File;
public class Helper {
static final String TAG = "Helper";
static final String WALLET_DIR = "Monerujo";
private static final String TAG = "Helper";
private static final String WALLET_DIR = "Monerujo";
static public File getStorageRoot(Context context) {
if (!isExternalStorageWritable()) {
@@ -43,7 +46,7 @@ public class Helper {
dir.mkdirs(); // try to make it
}
if (!dir.isDirectory()) {
String msg = "Directory " + dir.getAbsolutePath() + " does not exists.";
String msg = "Directory " + dir.getAbsolutePath() + " does not exist.";
Log.e(TAG, msg);
throw new IllegalStateException(msg);
}
@@ -56,7 +59,7 @@ public class Helper {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_DENIED) {
Log.d("permission", "permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
Log.d(TAG, "Permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
context.requestPermissions(permissions, PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
return false;
@@ -79,10 +82,29 @@ public class Helper {
/* Checks if external storage is available for read and write */
static public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
return Environment.MEDIA_MOUNTED.equals(state);
}
static public void showKeyboard(Activity act) {
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(act.getCurrentFocus(), InputMethodManager.SHOW_IMPLICIT);
}
static public void hideKeyboard(Activity act) {
if (act.getCurrentFocus() == null) {
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
} else {
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow((null == act.getCurrentFocus()) ? null : act.getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
static public void showKeyboard(Dialog dialog) {
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
static public void hideKeyboardAlways(Activity act) {
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.util;
import android.os.Parcel;
import android.os.Parcelable;
import com.m2049r.xmrwallet.model.PendingTransaction;
// https://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents
public class TxData implements Parcelable {
public TxData(String dst_addr,
String paymentId,
long amount,
int mixin,
PendingTransaction.Priority priority) {
this.dst_addr = dst_addr;
this.paymentId = paymentId;
this.amount = amount;
this.mixin = mixin;
this.priority = priority;
}
public String dst_addr;
public String paymentId;
public long amount;
public int mixin;
public PendingTransaction.Priority priority;
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(dst_addr);
out.writeString(paymentId);
out.writeLong(amount);
out.writeInt(mixin);
out.writeInt(priority.getValue());
}
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
public static final Parcelable.Creator<TxData> CREATOR = new Parcelable.Creator<TxData>() {
public TxData createFromParcel(Parcel in) {
return new TxData(in);
}
public TxData[] newArray(int size) {
return new TxData[size];
}
};
private TxData(Parcel in) {
dst_addr = in.readString();
paymentId = in.readString();
amount = in.readLong();
mixin = in.readInt();
priority = PendingTransaction.Priority.fromInteger(in.readInt());
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("dst_addr:");
sb.append(dst_addr);
sb.append(",paymentId:");
sb.append(paymentId);
sb.append(",amount:");
sb.append(amount);
sb.append(",mixin:");
sb.append(mixin);
sb.append(",priority:");
sb.append(priority.toString());
return sb.toString();
}
}

View File

@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.5,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zm6.5,-6v-5.5c0,-3.07 -2.13,-5.64 -5,-6.32V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5v0.68c-2.87,0.68 -5,3.25 -5,6.32V16l-2,2v1h17v-1l-2,-2z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-.25 1.97,-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01.25,-1.97.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z" />
</vector>

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<EditText
android:id="@+id/etWalletName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/generate_name_hint"
android:imeOptions="actionNext"
android:inputType="text"
android:maxLines="1"
android:textAlignment="center"
android:textSize="16sp" />
<EditText
android:id="@+id/etWalletPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/generate_password_hint"
android:imeOptions="actionNext"
android:inputType="text"
android:textAlignment="center"
android:textSize="16sp" />
</LinearLayout>
<EditText
android:id="@+id/etWalletMnemonic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/generate_mnemonic_hint"
android:imeOptions="actionNext"
android:inputType="textMultiLine"
android:textAlignment="center"
android:textSize="16sp" />
<EditText
android:id="@+id/etWalletAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/generate_address_hint"
android:imeOptions="actionNext"
android:inputType="textMultiLine"
android:textAlignment="center"
android:textSize="16sp" />
<LinearLayout
android:id="@+id/llRestoreKeys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<EditText
android:id="@+id/etWalletViewKey"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/generate_viewkey_hint"
android:imeOptions="actionNext"
android:inputType="textMultiLine"
android:textAlignment="center"
android:textSize="16sp" />
<EditText
android:id="@+id/etWalletSpendKey"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/generate_spendkey_hint"
android:imeOptions="actionNext"
android:inputType="textMultiLine"
android:textAlignment="center"
android:textSize="16sp" />
</LinearLayout>
<EditText
android:id="@+id/etWalletRestoreHeight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/generate_restoreheight_hint"
android:imeOptions="actionDone"
android:inputType="number"
android:textAlignment="center"
android:textSize="16sp"
android:visibility="gone" />
<Button
android:id="@+id/bGenerate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="@color/colorPrimary"
android:enabled="false"
android:text="@string/generate_buttonGenerate" />
</LinearLayout>

View File

@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8sp"
android:orientation="vertical">
<ProgressBar
android:id="@+id/pbProgress"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="@+id/tvWalletLabel"
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/generate_wallet_label"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletPasswordLabel"
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/generate_password_label"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="@+id/tvWalletName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="***"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
</LinearLayout>
<TextView
android:id="@+id/tvWalletMnemonicLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/generate_mnemonic_label"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletMnemonic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletAddressLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/generate_address_label"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:selectAllOnFocus="true"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textIsSelectable="true"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletViewKeyLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/generate_viewkey_label"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletViewKey"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:selectAllOnFocus="true"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textIsSelectable="true"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletSpendKeyLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/generate_spendkey_label"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/tvWalletSpendKey"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:selectAllOnFocus="true"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textIsSelectable="true"
android:textSize="16sp" />
<Button
android:id="@+id/bAccept"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/colorPrimary"
android:text="@string/generate_button_accept"
android:visibility="gone" />
</LinearLayout>

Some files were not shown because too many files have changed in this diff Show More