mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-03 08:23:04 +02:00
Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2d42a0287d | ||
![]() |
2ebb9d0650 | ||
![]() |
30792c53c0 | ||
![]() |
3846a0c391 | ||
![]() |
c66ebd654a | ||
![]() |
186ed5cd39 | ||
![]() |
e39cd1c988 | ||
![]() |
39d9c4d0c3 | ||
![]() |
e4562f07a4 | ||
![]() |
b3ea4540a1 | ||
![]() |
ea7c7d2fdb | ||
![]() |
8ff8be6f60 | ||
![]() |
b5ded700fe | ||
![]() |
a5527d4efd | ||
![]() |
a007810824 | ||
![]() |
a634cf18b1 | ||
![]() |
0b2fa08df8 | ||
![]() |
191aa6ac22 | ||
![]() |
a82a90575d | ||
![]() |
2e04046f50 | ||
![]() |
c11d577c5f | ||
![]() |
74b2dd209c | ||
![]() |
cb1d541474 | ||
![]() |
807d217aac | ||
![]() |
0421bcfac3 | ||
![]() |
b6c4e06fda | ||
![]() |
3ee8343074 | ||
![]() |
110621824a | ||
![]() |
7194580fbe | ||
![]() |
48dcd37740 | ||
![]() |
8e619756b9 | ||
![]() |
6c6b47db7d | ||
![]() |
a126844272 | ||
![]() |
9b3086ff2e | ||
![]() |
89d1842d59 | ||
![]() |
d44067e952 | ||
![]() |
0370eaa619 | ||
![]() |
35c393495a | ||
![]() |
f19618e017 | ||
![]() |
3a68802ae7 | ||
![]() |
344eeb7a3b | ||
![]() |
4ad58684b4 | ||
![]() |
30e35a895d | ||
![]() |
37414be4bf | ||
![]() |
a37ca4c0e5 | ||
![]() |
408b1a68d0 | ||
![]() |
40da44222e | ||
![]() |
b0efdca928 | ||
![]() |
d61198b47f | ||
![]() |
62433f6e10 | ||
![]() |
c9ae39508f | ||
![]() |
44836a24bb | ||
![]() |
80e60bd0c8 | ||
![]() |
9f38b957e1 | ||
![]() |
032aa24ab5 | ||
![]() |
afc45e1cbc | ||
![]() |
bd598deddd | ||
![]() |
952fb3a7f1 | ||
![]() |
fb62074d20 | ||
![]() |
56132e26ed | ||
![]() |
3239bdeb33 | ||
![]() |
142885821e | ||
![]() |
34941c599a | ||
![]() |
58c8f1896c | ||
![]() |
6611539491 | ||
![]() |
69729e5257 | ||
![]() |
535158c5e9 | ||
![]() |
61e2d880c2 | ||
![]() |
72889fcdde | ||
![]() |
905ee8b8a9 | ||
![]() |
81a9aa6938 | ||
![]() |
046238a29f | ||
![]() |
9751825ed7 | ||
![]() |
c19ee65dd1 | ||
![]() |
282f00959d | ||
![]() |
104a6063a3 | ||
![]() |
95e47e3407 |
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -1 +1,2 @@
|
||||
workspace.xml
|
||||
markdown-navigator*
|
||||
|
50
README.md
50
README.md
@@ -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
1
app/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.externalNativeBuild
|
||||
build
|
||||
app.iml
|
||||
|
147
app/app.iml
147
app/app.iml
@@ -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>
|
@@ -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 {
|
||||
|
@@ -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
381
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
381
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GenerateReviewFragment extends Fragment {
|
||||
static final String TAG = "GenerateReviewFragment";
|
||||
static final public String VIEW_DETAILS = "details";
|
||||
static final public String VIEW_ACCEPT = "accept";
|
||||
static final public String VIEW_WALLET = "wallet";
|
||||
|
||||
ProgressBar pbProgress;
|
||||
TextView tvWalletName;
|
||||
TextView tvWalletPassword;
|
||||
TextView tvWalletAddress;
|
||||
TextView tvWalletMnemonic;
|
||||
TextView tvWalletViewKey;
|
||||
TextView tvWalletSpendKey;
|
||||
Button bAccept;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.gen_review_fragment, container, false);
|
||||
|
||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||
tvWalletName = (TextView) view.findViewById(R.id.tvWalletName);
|
||||
tvWalletPassword = (TextView) view.findViewById(R.id.tvWalletPassword);
|
||||
tvWalletAddress = (TextView) view.findViewById(R.id.tvWalletAddress);
|
||||
tvWalletViewKey = (TextView) view.findViewById(R.id.tvWalletViewKey);
|
||||
tvWalletSpendKey = (TextView) view.findViewById(R.id.tvWalletSpendKey);
|
||||
tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
|
||||
|
||||
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||
|
||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||
tvWalletMnemonic.setTextIsSelectable(testnet);
|
||||
tvWalletSpendKey.setTextIsSelectable(testnet);
|
||||
|
||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
acceptWallet();
|
||||
}
|
||||
});
|
||||
|
||||
showProgress();
|
||||
|
||||
Bundle b = getArguments();
|
||||
String type = b.getString("type");
|
||||
if (!type.equals(VIEW_WALLET)) {
|
||||
String name = b.getString("name");
|
||||
String password = b.getString("password");
|
||||
tvWalletName.setText(new File(name).getName());
|
||||
show(name, password, type);
|
||||
} else {
|
||||
show(walletCallback.getWallet(), null, type);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
private void acceptWallet() {
|
||||
String name = tvWalletName.getText().toString();
|
||||
String password = tvWalletPassword.getText().toString();
|
||||
bAccept.setEnabled(false);
|
||||
acceptCallback.onAccept(name, password);
|
||||
}
|
||||
|
||||
private void show(final String walletPath, final String password, final String type) {
|
||||
new Thread(null,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
show(wallet, password, type);
|
||||
wallet.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
, "DetailsReview", MoneroHandlerThread.THREAD_STACK_SIZE).start();
|
||||
}
|
||||
|
||||
private void show(final Wallet wallet, final String password, final String type) {
|
||||
if (type.equals(GenerateReviewFragment.VIEW_ACCEPT)) {
|
||||
tvWalletPassword.setText(password);
|
||||
bAccept.setVisibility(View.VISIBLE);
|
||||
bAccept.setEnabled(true);
|
||||
}
|
||||
tvWalletName.setText(wallet.getName());
|
||||
tvWalletAddress.setText(wallet.getAddress());
|
||||
tvWalletMnemonic.setText(wallet.getSeed());
|
||||
tvWalletViewKey.setText(wallet.getSecretViewKey());
|
||||
String spend = wallet.isWatchOnly() ? "" : "not available - use seed for recovery";
|
||||
if (spend.length() > 0) { //TODO should be == 64, but spendkey is not in the API yet
|
||||
tvWalletSpendKey.setText(spend);
|
||||
} else {
|
||||
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
|
||||
}
|
||||
hideProgress();
|
||||
}
|
||||
|
||||
GenerateReviewFragment.Listener acceptCallback = null;
|
||||
GenerateReviewFragment.ListenerWithWallet walletCallback = null;
|
||||
|
||||
public interface Listener {
|
||||
void onAccept(String name, String password);
|
||||
}
|
||||
|
||||
public interface ListenerWithWallet {
|
||||
Wallet getWallet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof GenerateReviewFragment.Listener) {
|
||||
this.acceptCallback = (GenerateReviewFragment.Listener) context;
|
||||
} else if (context instanceof GenerateReviewFragment.ListenerWithWallet) {
|
||||
this.walletCallback = (GenerateReviewFragment.ListenerWithWallet) context;
|
||||
} else {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
|
||||
public void showProgress() {
|
||||
pbProgress.setIndeterminate(true);
|
||||
pbProgress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void hideProgress() {
|
||||
pbProgress.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
439
app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
Normal file
439
app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
398
app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Normal file
398
app/src/main/java/com/m2049r/xmrwallet/SendFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
266
app/src/main/java/com/m2049r/xmrwallet/TxFragment.java
Normal file
266
app/src/main/java/com/m2049r/xmrwallet/TxFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
274
app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
Normal file
274
app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,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);
|
||||
}
|
||||
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.model;
|
||||
|
||||
public class PendingTransaction {
|
||||
static {
|
||||
System.loadLibrary("monerujo");
|
||||
}
|
||||
|
||||
public long handle;
|
||||
|
||||
PendingTransaction(long handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
Status_Ok,
|
||||
Status_Error,
|
||||
Status_Critical
|
||||
}
|
||||
|
||||
public enum Priority {
|
||||
Priority_Low(1),
|
||||
Priority_Medium(2),
|
||||
Priority_High(3),
|
||||
Priority_Last(4);
|
||||
|
||||
public static Priority fromInteger(int n) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
return Priority_Low;
|
||||
case 2:
|
||||
return Priority_Medium;
|
||||
case 3:
|
||||
return Priority_High;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private int value;
|
||||
|
||||
Priority(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return Status.values()[getStatusJ()];
|
||||
}
|
||||
|
||||
public native int getStatusJ();
|
||||
|
||||
public native String getErrorString();
|
||||
|
||||
// commit transaction or save to file if filename is provided.
|
||||
public native boolean commit(String filename, boolean overwrite);
|
||||
|
||||
public native long getAmount();
|
||||
|
||||
public native long getDust();
|
||||
|
||||
public native long getFee();
|
||||
|
||||
public native String getFirstTxId();
|
||||
|
||||
public native long getTxCount();
|
||||
|
||||
}
|
@@ -1,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();
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
59
app/src/main/java/com/m2049r/xmrwallet/model/Transfer.java
Normal file
59
app/src/main/java/com/m2049r/xmrwallet/model/Transfer.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2017 m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.m2049r.xmrwallet.util.TxData;
|
||||
|
||||
public class Transfer implements Parcelable {
|
||||
public long amount;
|
||||
public String address;
|
||||
|
||||
public Transfer(long amount, String address) {
|
||||
this.amount = amount;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeLong(amount);
|
||||
out.writeString(address);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Transfer> CREATOR = new Parcelable.Creator<Transfer>() {
|
||||
public Transfer createFromParcel(Parcel in) {
|
||||
return new Transfer(in);
|
||||
}
|
||||
|
||||
public Transfer[] newArray(int size) {
|
||||
return new Transfer[size];
|
||||
}
|
||||
};
|
||||
|
||||
private Transfer(Parcel in) {
|
||||
amount = in.readLong();
|
||||
address = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@@ -1,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 ¬e) = 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;
|
||||
|
@@ -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.
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
|
93
app/src/main/java/com/m2049r/xmrwallet/util/TxData.java
Normal file
93
app/src/main/java/com/m2049r/xmrwallet/util/TxData.java
Normal 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();
|
||||
}
|
||||
}
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
107
app/src/main/res/layout/gen_fragment.xml
Normal file
107
app/src/main/res/layout/gen_fragment.xml
Normal 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>
|
160
app/src/main/res/layout/gen_review_fragment.xml
Normal file
160
app/src/main/res/layout/gen_review_fragment.xml
Normal 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
Reference in New Issue
Block a user