wownero
/
wownerujo
Archived
4
0
Fork 0
async wallet load / close by service
wakelock & async loading / closing looks good
progress indicator
ode cleanup
added license boilerplates
upstream
m2049r 7 years ago
parent e576dedb9b
commit 2682399600

2
.gitignore vendored

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

1
.idea/.gitignore vendored

@ -0,0 +1 @@
workspace.xml

@ -0,0 +1 @@
xmrwallet

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

@ -0,0 +1,3 @@
<component name="CopyrightManager">
<settings default="" />
</component>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="animated-vector-drawable-25.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/c5daa70b6947fa9fd8a9960e661cc14fc4797397/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/c5daa70b6947fa9fd8a9960e661cc14fc4797397/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/animated-vector-drawable/25.3.1/animated-vector-drawable-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="appcompat-v7-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/7347280c7c5efbce562b3f7493acce3ce62120aa/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/7347280c7c5efbce562b3f7493acce3ce62120aa/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/appcompat-v7/25.3.1/appcompat-v7-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="cardview-v7-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/d3101339ab3be4a16068a03e764036d173229f64/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/d3101339ab3be4a16068a03e764036d173229f64/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/cardview-v7/25.3.1/cardview-v7-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="constraint-layout-1.0.2">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/983cd9976ef510b2538361561f2ee91f1200f245/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/983cd9976ef510b2538361561f2ee91f1200f245/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="constraint-layout-solver-1.0.2">
<CLASSES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/m2repository/com/android/support/constraint/constraint-layout-solver/1.0.2/constraint-layout-solver-1.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="design-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/222602355d1fc232e06a3e23c06dc49c03836f7a/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/222602355d1fc232e06a3e23c06dc49c03836f7a/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/design/25.3.1/design-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="espresso-core-2.2.2">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/d505abdc89cc7d1b938ec3f95e87d4323360fa14/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/d505abdc89cc7d1b938ec3f95e87d4323360fa14/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/espresso/espresso-core/2.2.2/espresso-core-2.2.2-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="espresso-idling-resource-2.2.2">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/0dcbbeb3c862ffabe5d9f3c1f70b25bfdf6c739e/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/0dcbbeb3c862ffabe5d9f3c1f70b25bfdf6c739e/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/espresso/espresso-idling-resource/2.2.2/espresso-idling-resource-2.2.2-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="exposed-instrumentation-api-publish-0.5">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/c11e9f250159df473b4fbff8b80f455f0be2e5b5/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/c11e9f250159df473b4fbff8b80f455f0be2e5b5/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/exposed-instrumentation-api-publish/0.5/exposed-instrumentation-api-publish-0.5-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="hamcrest-core-1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b/hamcrest-core-1.3-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="hamcrest-integration-1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-integration/1.3/5de0c73fef18917cd85d0ab70bb23818685e4dfd/hamcrest-integration-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="hamcrest-library-1.3">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-library/1.3/4785a3c21320980282f9f33d0d1264a69040538f/hamcrest-library-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="javawriter-2.1.1">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.squareup/javawriter/2.1.1/67ff45d9ae02e583d0f9b3432a5ebbe05c30c966/javawriter-2.1.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="javax.annotation-api-1.2">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/javax.annotation/javax.annotation-api/1.2/479c1e06db31c432330183f5cae684163f186146/javax.annotation-api-1.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="javax.inject-1">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="jsr305-2.0.1">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/2.0.1/516c03b21d50a644d538de0f0369c620989cd8f0/jsr305-2.0.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="junit-4.12">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58ec/junit-4.12.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/junit/junit/4.12/a6c32b40bf3d76eca54e3c601e5d1470c86fcdfa/junit-4.12-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="recyclerview-v7-25.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/99e5fdc3d331d7083d1b3759b72d024c2f736dcd/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/99e5fdc3d331d7083d1b3759b72d024c2f736dcd/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/recyclerview-v7/25.3.1/recyclerview-v7-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="rules-0.5">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/8f8d46a3318b85241b55e25415619e9017c0aef1/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/8f8d46a3318b85241b55e25415619e9017c0aef1/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/rules/0.5/rules-0.5-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="runner-0.5">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/a3a29c4e90c979d7576a0a7d8450261e0065a0a8/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/a3a29c4e90c979d7576a0a7d8450261e0065a0a8/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/test/runner/0.5/runner-0.5-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="support-annotations-25.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-annotations/25.3.1/support-annotations-25.3.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-annotations/25.3.1/support-annotations-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="support-compat-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/bfee7899a02ec429f8d6fbb22abb30af9d75dd54/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/bfee7899a02ec429f8d6fbb22abb30af9d75dd54/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-compat/25.3.1/support-compat-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="support-core-ui-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/f1e0938f7953f4d9d6e09e6205aea1c4ea1bf919/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/f1e0938f7953f4d9d6e09e6205aea1c4ea1bf919/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-core-ui/25.3.1/support-core-ui-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="support-core-utils-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/3399641f4104cc67bc990816452765709c509ff9/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/3399641f4104cc67bc990816452765709c509ff9/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-core-utils/25.3.1/support-core-utils-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="support-fragment-25.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/3f5c9811e6cfbd571b84d0dbb634b48dfe989015/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/3f5c9811e6cfbd571b84d0dbb634b48dfe989015/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-fragment/25.3.1/support-fragment-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="support-media-compat-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/7ed270352f6e04a617f3ff349bf4590f91afd032/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/7ed270352f6e04a617f3ff349bf4590f91afd032/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-media-compat/25.3.1/support-media-compat-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="support-v4-25.3.1">
<CLASSES>
<root url="file://$USER_HOME$/.android/build-cache/00ab1c7e820f681dc2b7ac4321cc1d73f2876d96/output/res" />
<root url="jar://$USER_HOME$/.android/build-cache/00ab1c7e820f681dc2b7ac4321cc1d73f2876d96/output/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="support-vector-drawable-25.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/e6ca1fb96a4aeca737119703e3fea72846da3ca1/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/e6ca1fb96a4aeca737119703e3fea72846da3ca1/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/support-vector-drawable/25.3.1/support-vector-drawable-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,12 @@
<component name="libraryTable">
<library name="transition-25.3.1">
<CLASSES>
<root url="jar://$USER_HOME$/.android/build-cache/1ff9f43f47f4f75d31b57959475cee7001de24ac/output/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.android/build-cache/1ff9f43f47f4f75d31b57959475cee7001de24ac/output/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/AppData/Local/Android/Sdk/extras/android/m2repository/com/android/support/transition/25.3.1/transition-25.3.1-sources.jar!/" />
</SOURCES>
</library>
</component>

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/xmrwallet.iml" filepath="$PROJECT_DIR$/xmrwallet.iml" />
</modules>
</component>
</project>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -0,0 +1,49 @@
# Monerujo
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)
- see the [FAQ](doc/FAQ.md)
### Disclaimer
This is my first serious Android App.
### 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)
- use your own daemon - it's easy
- screen stays on until first sync is complete
### 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
### Issues
- screen rotation crashes the app
- turning the display off/on during sync stops sync
### HOW TO BUILD
No need to build. Binaries are included:
- openssl-1.0.2l
- monero-v0.10.3.1 + pull requests #2238 & #2239
- boost_1_64_0
If you want to build - fire up Android Studio and build. Also you can rebuild all of the above.

2
app/.gitignore vendored

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

@ -0,0 +1,172 @@
cmake_minimum_required(VERSION 3.4.1)
message(STATUS ABI_INFO = ${ANDROID_ABI})
add_library( monerujo
SHARED
src/main/cpp/monerujo.cpp )
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
############
# OpenSSL
############
add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
############
# Boost
############
add_library(boost_chrono STATIC IMPORTED)
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_chrono.a)
add_library(boost_date_time STATIC IMPORTED)
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_date_time.a)
add_library(boost_filesystem STATIC IMPORTED)
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_filesystem.a)
add_library(boost_program_options STATIC IMPORTED)
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_program_options.a)
add_library(boost_regex STATIC IMPORTED)
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_regex.a)
add_library(boost_serialization STATIC IMPORTED)
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_serialization.a)
add_library(boost_system STATIC IMPORTED)
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_system.a)
add_library(boost_thread STATIC IMPORTED)
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_thread.a)
add_library(boost_wserialization STATIC IMPORTED)
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_wserialization.a)
#############
# Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct)
#############
add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
add_library(cryptonote_core STATIC IMPORTED)
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.a)
add_library(cryptonote_basic STATIC IMPORTED)
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.a)
add_library(mnemonics STATIC IMPORTED)
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.a)
add_library(common STATIC IMPORTED)
set_target_properties(common PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.a)
add_library(cncrypto STATIC IMPORTED)
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.a)
add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
#####
add_library(p2p STATIC IMPORTED)
set_target_properties(p2p PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.a)
add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.a)
add_library(lmdb STATIC IMPORTED)
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.a)
add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.a)
add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
####
add_library(epee STATIC IMPORTED)
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libepee.a)
add_library(blocks STATIC IMPORTED)
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblocks.a)
add_library(miniupnpc STATIC IMPORTED)
set_target_properties(miniupnpc PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libminiupnpc.a)
#############
# System
#############
find_library( log-lib log )
include_directories( ${EXTERNAL_LIBS_DIR}/monero/include )
message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR})
target_link_libraries( monerujo
wallet
cryptonote_core
cryptonote_basic
mnemonics
ringct
common
cncrypto
blockchain_db
lmdb
#easylogging # not for 0.10.3.1
unbound
p2p
epee
blocks
miniupnpc
boost_chrono
boost_date_time
boost_filesystem
boost_program_options
boost_regex
boost_serialization
boost_system
boost_thread
boost_wserialization
ssl
crypto
${log-lib}
)

@ -0,0 +1,147 @@
<?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>

@ -0,0 +1,50 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 2
versionName "0.2.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments '-DANDROID_STL=c++_shared'
}
}
ndk {
abiFilters 'armeabi-v7a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
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'
testCompile 'junit:junit:4.12'
}

@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\Test\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.m2049r.xmrwallet">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".WalletActivity"
android:label="@string/wallet_activity_name"
android:launchMode="singleTop"></activity>
<activity
android:name=".LoginActivity"
android:label="@string/app_name">
<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

@ -0,0 +1,51 @@
/**
* 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
#include <jni.h>
/*
#include <android/log.h>
#define LOG_TAG "[NDK]"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
*/
jfieldID getHandleField(JNIEnv *env, jobject obj, const char* fieldName = "handle") {
jclass c = env->GetObjectClass(obj);
return env->GetFieldID(c, fieldName, "J"); // of type long
}
template <typename T>
T *getHandle(JNIEnv *env, jobject obj, const char* fieldName = "handle") {
jlong handle = env->GetLongField(obj, getHandleField(env, obj, fieldName));
return reinterpret_cast<T *>(handle);
}
void setHandleFromLong(JNIEnv *env, jobject obj, jlong handle) {
env->SetLongField(obj, getHandleField(env, obj), handle);
}
template <typename T>
void setHandle(JNIEnv *env, jobject obj, T *t) {
jlong handle = reinterpret_cast<jlong>(t);
setHandleFromLong(env, obj, handle);
}
#endif //XMRWALLET_WALLET_LIB_H

@ -0,0 +1,353 @@
/**
* 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.
*/
package com.m2049r.xmrwallet;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class LoginActivity extends Activity {
static final String TAG = "LoginActivity";
ListView listView;
List<String> walletList = new ArrayList<>();
List<String> displayedList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
final EditText etDaemonAddress = (EditText) findViewById(R.id.etDaemonAddress);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
etDaemonAddress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(etDaemonAddress, InputMethodManager.SHOW_IMPLICIT);
}
});
etDaemonAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
return false;
}
return false;
}
});
ToggleButton tbMainNet = (ToggleButton) findViewById(R.id.tbMainNet);
tbMainNet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean mainnet = ((ToggleButton) v).isChecked(); // current state
savePrefs(true); // use previous state as we just clicked it
if (mainnet) {
setDaemon(daemonMainNet);
} else {
setDaemon(daemonTestNet);
}
filterList();
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
}
});
loadPrefs();
filterList();
listView = (ListView) findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, this.displayedList);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EditText tvDaemonAddress = (EditText) findViewById(R.id.etDaemonAddress);
if (tvDaemonAddress.getText().toString().length() == 0) {
Toast.makeText(LoginActivity.this, getString(R.string.prompt_daemon_missing), Toast.LENGTH_LONG).show();
return;
}
String itemValue = (String) listView.getItemAtPosition(position);
if ((isMainNet() && itemValue.charAt(1) != '4')
|| (!isMainNet() && itemValue.charAt(1) != '9')) {
Toast.makeText(LoginActivity.this, getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
return;
}
final int preambleLength = "[123456] ".length();
if (itemValue.length() <= (preambleLength)) {
Toast.makeText(LoginActivity.this, "something's wrong", Toast.LENGTH_LONG).show();
return;
}
String wallet = itemValue.substring(preambleLength);
promptPassword(wallet);
}
});
if (Helper.getWritePermission(this)) {
new LoadListTask().execute();
} else {
Log.i(TAG, "Waiting for permissions");
}
}
// adapted from http://www.mkyong.com/android/android-prompt-user-input-dialog-example/
void promptPassword(final String wallet) {
Context context = LoginActivity.this;
LayoutInflater li = LayoutInflater.from(context);
View promptsView = li.inflate(R.layout.prompt_password, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setView(promptsView);
final EditText etPassword = (EditText) promptsView.findViewById(R.id.etPassword);
final TextView tvPasswordLabel = (TextView) promptsView.findViewById(R.id.tvPasswordLabel);
tvPasswordLabel.setText(LoginActivity.this.getString(R.string.prompt_password) + " " + wallet);
// set dialog message
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
String pass = etPassword.getText().toString();
processPasswordEntry(wallet, pass);
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
dialog.cancel();
}
});
final AlertDialog alertDialog = alertDialogBuilder.create();
// request keyboard
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
// accept keyboard "ok"
etPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
String pass = etPassword.getText().toString();
alertDialog.cancel();
processPasswordEntry(wallet, pass);
return false;
}
return false;
}
});
alertDialog.show();
}
private void processPasswordEntry(String walletName, String pass) {
if (checkWalletPassword(walletName, pass)) {
startWallet(walletName, pass);
} else {
Toast.makeText(this, getString(R.string.bad_password), Toast.LENGTH_SHORT).show();
}
}
private boolean checkWalletPassword(String walletName, String password) {
String walletPath = new File(Helper.getStorageRoot(getApplicationContext()),
walletName + ".keys").getAbsolutePath();
// only test view key
return WalletManager.getInstance().verifyWalletPassword(walletPath, password, true);
}
@Override
protected void onPause() {
Log.d(TAG, "onPause()");
savePrefs(false);
super.onPause();
}
boolean isMainNet() {
ToggleButton tbMainNet = (ToggleButton) findViewById(R.id.tbMainNet);
return tbMainNet.isChecked();
}
void setMainNet(boolean mainnet) {
ToggleButton tbMainNet = (ToggleButton) findViewById(R.id.tbMainNet);
tbMainNet.setChecked(mainnet);
}
String getDaemon() {
EditText tvDaemonAddress = (EditText) findViewById(R.id.etDaemonAddress);
return tvDaemonAddress.getText().toString();
}
void setDaemon(String address) {
EditText tvDaemonAddress = (EditText) findViewById(R.id.etDaemonAddress);
tvDaemonAddress.setText(address);
}
private static final String PREF_DAEMON_TESTNET = "daemon_testnet";
private static final String PREF_DAEMON_MAINNET = "daemon_mainnet";
private static final String PREF_MAINNET = "mainnet";
private String daemonTestNet;
private String daemonMainNet;
void loadPrefs() {
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
boolean mainnet = sharedPref.getBoolean(PREF_MAINNET, false);
daemonMainNet = sharedPref.getString(PREF_DAEMON_MAINNET, "localhost:18081");
daemonTestNet = sharedPref.getString(PREF_DAEMON_TESTNET, "localhost:28081");
setMainNet(mainnet);
if (mainnet) {
setDaemon(daemonMainNet);
} else {
setDaemon(daemonTestNet);
}
}
void savePrefs(boolean usePreviousState) {
// save the daemon address for the net
boolean mainnet = isMainNet() ^ usePreviousState;
String daemon = getDaemon();
if (mainnet) {
daemonMainNet = daemon;
} else {
daemonTestNet = daemon;
}
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(PREF_MAINNET, mainnet);
editor.putString(PREF_DAEMON_MAINNET, daemonMainNet);
editor.putString(PREF_DAEMON_TESTNET, daemonTestNet);
editor.apply();
}
void startWallet(String walletName, String walletPassword) {
Log.d(TAG, "startWallet()");
savePrefs(false);
boolean testnet = !isMainNet();
String daemon = getDaemon();
Intent intent = new Intent(getApplicationContext(), WalletActivity.class);
if (!daemon.contains(":")) {
daemon = daemon + (testnet ? ":28081" : ":18081");
}
WalletManager.getInstance().setDaemon(daemon, testnet);
intent.putExtra(WalletActivity.REQUEST_ID, walletName);
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
startActivity(intent);
}
private void filterList() {
displayedList.clear();
char x = isMainNet() ? '4' : '9';
for (String s : walletList) {
if (s.charAt(1) == x) displayedList.add(s);
}
}
private class LoadListTask extends AsyncTask<String, Void, Integer> {
protected void onPreExecute() {
//Toast.makeText(LoginActivity.this, getString(R.string.status_walletlist_loading), Toast.LENGTH_LONG).show();
}
protected Integer doInBackground(String... params) {
WalletManager mgr = WalletManager.getInstance();
List<WalletManager.WalletInfo> walletInfos =
mgr.findWallets(Helper.getStorageRoot(getApplicationContext()));
walletList.clear();
for (WalletManager.WalletInfo walletInfo : walletInfos) {
Log.d(TAG, walletInfo.address);
String displayAddress = walletInfo.address;