1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-19 20:40:50 +02:00

Compare commits

..

13 Commits

Author SHA1 Message Date
m2049r
61e2d880c2 Merge pull request #6 from m2049r/docs
updated docs
2017-08-14 10:48:38 +02:00
m2049r
72889fcdde Create BUILDING-external-libs.md
Update README.md
2017-08-14 10:47:04 +02:00
m2049r
905ee8b8a9 Merge pull request #5 from m2049r/features
allow only portrait
2017-08-14 10:02:50 +02:00
m2049r
81a9aa6938 allow only portrait
remove some debug messages
2017-08-14 10:01:22 +02:00
m2049r
046238a29f Merge pull request #4 from m2049r/features
lots of tweaks
2017-08-14 09:30:16 +02:00
m2049r
9751825ed7 stack size for background thread set to 5MB (monero dafault)
so no need to use heap for slow_hash
recompiled monero without USE_HEAP
2017-08-14 09:26:59 +02:00
m2049r
c19ee65dd1 UI & progress bar tweaks
service start/stop in activity onCreate/onDestroy
update continues in background if screen turned off
2017-08-13 15:39:11 +02:00
m2049r
282f00959d reverted libwallet crypto CMake 2017-08-13 00:29:58 +02:00
m2049r
104a6063a3 Merge pull request #3 from m2049r/features
check daemon availability & save only on first sync
2017-08-12 19:59:45 +02:00
m2049r
95e47e3407 check daemon availability
show txs immediately
only save on first sync

no store on close

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

2
.gitignore vendored Normal file
View File

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

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

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

3068
.idea/workspace.xml generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,42 +10,40 @@ Another Android Monero Wallet
### Disclaimer ### Disclaimer
This is my first serious Android App. This is my first serious Android App.
### Notes ### Random Notes
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/ - Based off monero v0.10.3.1 with pull requests #2238, #2239 and #2289 applied => so can be used in mainnet!
- Special thanks to /u/gkruja for inspiration to pick this project up again
- Based off monero v0.10.3.1 with pull requests #2238 & #2239 applied => so can be used in mainnet!
- currently only android32 - currently only android32
- sorry for my messups in github - currently only use is checking incoming/outgoing transactions
- this is more of a proof of concept
- currently only use is checking incoming/outgoing transactions
- works in testnet & mainnet (please use your own daemons) - works in testnet & mainnet (please use your own daemons)
- takes forever to sync on mainnet (even with own daemon) - takes forever to sync on mainnet (even with own daemon) - due to 32-bit architecture
- use your own daemon - it's easy - use your own daemon - it's easy
- screen stays on until first sync is complete - screen stays on until first sync is complete
- saves wallet only on first sync
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
### TODO ### TODO
- don't have the screen on for first sync - use IntentService with WakeLock instead?
- make it pretty - make it pretty
- show current block height - is that relevant? - adjust layout so we can use bigger font sizes (maybe show only 5 decimal places instead of 12 in main view)
- License Dialog - review visibility of methods/classes
- support for right-to-left layouts
- visibility of methods/classes
- adjust layout so we can use bigger font sizes
- sensible error dialogs (e.g. when no write permissions granted) instead of just crashing on purpose - sensible 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 - 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) - check licenses of included libraries; License Dialog
- currently loading in background thread produces segfaults in JNI - ~~provide detailed build instructions for third party binaries~~
- check licenses of included libraries - ~~sensible loading/saving progress bars instead of just freezing up~~
- ~~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~~
### Issues ### Issues
- occasional crashes ... - ~~screen rotation crashes the app~~
- ~~turning the display off/on during sync stops sync~~
### HOW TO BUILD ### HOW TO BUILD
No need to build. Binaries are included: No need to build. Binaries are included:
- openssl-1.0.2l - openssl-1.0.2l
- monero-v0.10.3.1 + pull requests #2238 & #2239 - monero-v0.10.3.1 + pull requests #2238, #2239 and #2289
- boost_1_64_0 - boost_1_64_0
If you want to build - fire up Android Studio and build. Also you can rebuild all of the above. If you want to build them yourself (recommended) check out [the instructions](doc/BUILDING-external-libs.md)
Then, fire up Android Studio and build the APK.

2
app/.gitignore vendored Normal file
View File

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

View File

@@ -11,13 +11,13 @@ set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
# OpenSSL # OpenSSL
############ ############
add_library(crypto SHARED IMPORTED) add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.so) ${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
add_library(ssl SHARED IMPORTED) add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.so) ${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
############ ############
# Boost # Boost
@@ -63,55 +63,55 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
# Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct) # Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct)
############# #############
add_library(wallet SHARED IMPORTED) add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
add_library(cryptonote_core SHARED IMPORTED) add_library(cryptonote_core STATIC IMPORTED)
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.a)
add_library(cryptonote_basic SHARED IMPORTED) add_library(cryptonote_basic STATIC IMPORTED)
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.a)
add_library(mnemonics SHARED IMPORTED) add_library(mnemonics STATIC IMPORTED)
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.a)
add_library(common SHARED IMPORTED) add_library(common STATIC IMPORTED)
set_target_properties(common PROPERTIES IMPORTED_LOCATION set_target_properties(common PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.a)
add_library(cncrypto SHARED IMPORTED) add_library(cncrypto STATIC IMPORTED)
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.a)
add_library(ringct SHARED IMPORTED) add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
##### #####
add_library(p2p SHARED IMPORTED) add_library(p2p STATIC IMPORTED)
set_target_properties(p2p PROPERTIES IMPORTED_LOCATION set_target_properties(p2p PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.a)
add_library(blockchain_db SHARED IMPORTED) add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.a)
add_library(lmdb SHARED IMPORTED) add_library(lmdb STATIC IMPORTED)
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.a)
add_library(easylogging SHARED IMPORTED) add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.a)
add_library(unbound SHARED IMPORTED) add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.so) ${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
#### ####
add_library(epee STATIC IMPORTED) add_library(epee STATIC IMPORTED)
@@ -141,9 +141,10 @@ target_link_libraries( monerujo
cryptonote_core cryptonote_core
cryptonote_basic cryptonote_basic
mnemonics mnemonics
cncrypto
ringct ringct
common common
cncrypto
blockchain_db blockchain_db
lmdb lmdb
#easylogging # not for 0.10.3.1 #easylogging # not for 0.10.3.1

View File

@@ -92,13 +92,21 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/cmake" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/cmake" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> <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-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/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" /> <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/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/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" /> <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/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" /> <excludeFolder url="file://$MODULE_DIR$/build/outputs" />

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet" applicationId "com.m2049r.xmrwallet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 25 targetSdkVersion 25
versionCode 1 versionCode 3
versionName "0.1" versionName "0.3.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View File

@@ -17,17 +17,28 @@
<activity <activity
android:name=".WalletActivity" android:name=".WalletActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/wallet_activity_name" android:label="@string/wallet_activity_name"
android:launchMode="singleTop"></activity> android:launchMode="singleTop"
android:screenOrientation="portrait"></activity>
<activity <activity
android:name=".LoginActivity" android:name=".LoginActivity"
android:label="@string/app_name"> android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service
android:name=".service.WalletService"
android:description="@string/service_description"
android:exported="false"
android:label="Monero Wallet Service" />
</application> </application>
</manifest> </manifest>

View File

@@ -1,3 +1,19 @@
/**
* 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.
*/
#include <inttypes.h> #include <inttypes.h>
#include "monerujo.h" #include "monerujo.h"
#include "wallet2_api.h" #include "wallet2_api.h"
@@ -336,15 +352,14 @@ Java_com_m2049r_xmrwallet_model_WalletManager_verifyWalletPassword(JNIEnv *env,
const char *_keys_file_name = env->GetStringUTFChars(keys_file_name, JNI_FALSE); const char *_keys_file_name = env->GetStringUTFChars(keys_file_name, JNI_FALSE);
const char *_password = env->GetStringUTFChars(password, JNI_FALSE); const char *_password = env->GetStringUTFChars(password, JNI_FALSE);
bool passwordOk = bool passwordOk =
Bitmonero::WalletManagerFactory::getWalletManager()->verifyWalletPassword( Bitmonero::WalletManagerFactory::getWalletManager()->verifyWalletPassword(
std::string(_keys_file_name), std::string(_password), watch_only); std::string(_keys_file_name), std::string(_password), watch_only);
env->ReleaseStringUTFChars(keys_file_name, _keys_file_name); env->ReleaseStringUTFChars(keys_file_name, _keys_file_name);
env->ReleaseStringUTFChars(password, _password); env->ReleaseStringUTFChars(password, _password);
return passwordOk; return passwordOk;
} }
JNIEXPORT jobject JNICALL JNIEXPORT jobject JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_findWallets(JNIEnv *env, jobject instance, Java_com_m2049r_xmrwallet_model_WalletManager_findWallets(JNIEnv *env, jobject instance,
jstring path) { jstring path) {
@@ -365,14 +380,15 @@ Java_com_m2049r_xmrwallet_model_WalletManager_getErrorString(JNIEnv *env, jobjec
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_setDaemonAddressJ(JNIEnv *env, jobject instance, Java_com_m2049r_xmrwallet_model_WalletManager_setDaemonAddressJ(JNIEnv *env, jobject instance,
jstring address) { jstring address) {
const char *_address = env->GetStringUTFChars(address, JNI_FALSE); const char *_address = env->GetStringUTFChars(address, JNI_FALSE);
Bitmonero::WalletManagerFactory::getWalletManager()->setDaemonAddress(std::string(_address)); Bitmonero::WalletManagerFactory::getWalletManager()->setDaemonAddress(std::string(_address));
env->ReleaseStringUTFChars(address, _address); env->ReleaseStringUTFChars(address, _address);
} }
// returns whether the daemon can be reached, and its version number
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_com_m2049r_xmrwallet_model_WalletManager_getConnectedDaemonVersion(JNIEnv *env, Java_com_m2049r_xmrwallet_model_WalletManager_getDaemonVersion(JNIEnv *env,
jobject instance) { jobject instance) {
uint32_t version; uint32_t version;
bool isConnected = bool isConnected =
@@ -449,11 +465,12 @@ Java_com_m2049r_xmrwallet_model_WalletManager_resolveOpenAlias(JNIEnv *env, jobj
// actually a WalletManager function, but logically in Wallet // actually a WalletManager function, but logically in Wallet
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_close(JNIEnv *env, jobject instance) { Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance); jobject walletInstance) {
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, walletInstance);
bool closeSuccess = Bitmonero::WalletManagerFactory::getWalletManager()->closeWallet(wallet); bool closeSuccess = Bitmonero::WalletManagerFactory::getWalletManager()->closeWallet(wallet);
if (closeSuccess) { if (closeSuccess) {
MyWalletListener *walletListener = getHandle<MyWalletListener>(env, instance, MyWalletListener *walletListener = getHandle<MyWalletListener>(env, walletInstance,
"listenerHandle"); "listenerHandle");
if (walletListener != nullptr) { if (walletListener != nullptr) {
walletListener->deleteGlobalJavaRef(env); walletListener->deleteGlobalJavaRef(env);
@@ -575,9 +592,9 @@ Java_com_m2049r_xmrwallet_model_Wallet_getFilename(JNIEnv *env, jobject instance
// virtual std::string keysFilename() const = 0; // virtual std::string keysFilename() const = 0;
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_com_m2049r_xmrwallet_model_Wallet_init(JNIEnv *env, jobject instance, Java_com_m2049r_xmrwallet_model_Wallet_initJ(JNIEnv *env, jobject instance,
jstring daemon_address, jstring daemon_address,
long upper_transaction_size_limit) { long upper_transaction_size_limit) {
// const std::string &daemon_username = "", const std::string &daemon_password = "") = 0; // const std::string &daemon_username = "", const std::string &daemon_password = "") = 0;
const char *_daemon_address = env->GetStringUTFChars(daemon_address, JNI_FALSE); const char *_daemon_address = env->GetStringUTFChars(daemon_address, JNI_FALSE);
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance); Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);

View File

@@ -1,6 +1,18 @@
// /**
// Created by m2049r on 15.04.2017. * Copyright (c) 2017 m2049r
// * <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef XMRWALLET_WALLET_LIB_H #ifndef XMRWALLET_WALLET_LIB_H
#define XMRWALLET_WALLET_LIB_H #define XMRWALLET_WALLET_LIB_H

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet; package com.m2049r.xmrwallet;
import android.app.Activity; import android.app.Activity;
@@ -9,6 +25,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
@@ -30,11 +47,19 @@ import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
public class LoginActivity extends Activity { public class LoginActivity extends Activity {
static final String TAG = "LoginActivity"; static final String TAG = "LoginActivity";
static final int MIN_DAEMON_VERSION = 65544;
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
ListView listView; ListView listView;
List<String> walletList = new ArrayList<>(); List<String> walletList = new ArrayList<>();
List<String> displayedList = new ArrayList<>(); List<String> displayedList = new ArrayList<>();
@@ -69,8 +94,12 @@ public class LoginActivity extends Activity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
boolean mainnet = ((ToggleButton) v).isChecked(); // current state boolean mainnet = ((ToggleButton) v).isChecked(); // current state
Log.d(TAG, "CLICK NET! mainnet=" + mainnet);
savePrefs(true); // use previous state as we just clicked it savePrefs(true); // use previous state as we just clicked it
if (mainnet) {
setDaemon(daemonMainNet);
} else {
setDaemon(daemonTestNet);
}
filterList(); filterList();
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged(); ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
} }
@@ -104,9 +133,17 @@ public class LoginActivity extends Activity {
final int preambleLength = "[123456] ".length(); final int preambleLength = "[123456] ".length();
if (itemValue.length() <= (preambleLength)) { if (itemValue.length() <= (preambleLength)) {
Toast.makeText(LoginActivity.this, "something's wrong", Toast.LENGTH_LONG).show(); Toast.makeText(LoginActivity.this, getString(R.string.panic), Toast.LENGTH_LONG).show();
return; return;
} }
setWalletDaemon();
if (!checkWalletDaemon()) {
Toast.makeText(LoginActivity.this, getString(R.string.warn_daemon_unavailable), Toast.LENGTH_LONG).show();
return;
}
// looking good
savePrefs(false);
String wallet = itemValue.substring(preambleLength); String wallet = itemValue.substring(preambleLength);
promptPassword(wallet); promptPassword(wallet);
@@ -180,6 +217,32 @@ public class LoginActivity extends Activity {
} }
} }
private boolean checkWalletDaemon() {
// if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy prevPolicy = StrictMode.getThreadPolicy();
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder(prevPolicy).permitNetwork().build();
StrictMode.setThreadPolicy(policy);
String d[] = WalletManager.getInstance().getDaemonAddress().split(":");
String host = d[0];
int port = Integer.parseInt(d[1]);
Socket socket = new Socket();
long a = new Date().getTime();
try {
socket.connect(new InetSocketAddress(host, port), DAEMON_TIMEOUT);
socket.close();
} catch (IOException ex) {
Log.d(TAG, "Cannot reach daemon " + host + ":" + port + " because " + ex.getLocalizedMessage());
return false;
} finally {
StrictMode.setThreadPolicy(prevPolicy);
}
long b = new Date().getTime();
Log.d(TAG, "Daemon is " + (b - a) + "ms away.");
int version = WalletManager.getInstance().getDaemonVersion();
Log.d(TAG, "Daemon is v" + version);
return (version >= MIN_DAEMON_VERSION);
}
private boolean checkWalletPassword(String walletName, String password) { private boolean checkWalletPassword(String walletName, String password) {
String walletPath = new File(Helper.getStorageRoot(getApplicationContext()), String walletPath = new File(Helper.getStorageRoot(getApplicationContext()),
walletName + ".keys").getAbsolutePath(); walletName + ".keys").getAbsolutePath();
@@ -187,7 +250,6 @@ public class LoginActivity extends Activity {
return WalletManager.getInstance().verifyWalletPassword(walletPath, password, true); return WalletManager.getInstance().verifyWalletPassword(walletPath, password, true);
} }
@Override @Override
protected void onPause() { protected void onPause() {
Log.d(TAG, "onPause()"); Log.d(TAG, "onPause()");
@@ -195,6 +257,12 @@ public class LoginActivity extends Activity {
super.onPause(); super.onPause();
} }
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume()");
}
boolean isMainNet() { boolean isMainNet() {
ToggleButton tbMainNet = (ToggleButton) findViewById(R.id.tbMainNet); ToggleButton tbMainNet = (ToggleButton) findViewById(R.id.tbMainNet);
return tbMainNet.isChecked(); return tbMainNet.isChecked();
@@ -255,20 +323,22 @@ public class LoginActivity extends Activity {
editor.apply(); editor.apply();
} }
void startWallet(String walletName, String walletPassword) { private void setWalletDaemon() {
Log.d(TAG, "startWallet()");
savePrefs(false);
EditText tvDaemonAddress = (EditText) findViewById(R.id.etDaemonAddress);
boolean testnet = !isMainNet(); boolean testnet = !isMainNet();
Intent intent = new Intent(getApplicationContext(), WalletActivity.class); String daemon = getDaemon();
String daemon = tvDaemonAddress.getText().toString();
if (!daemon.contains(":")) { if (!daemon.contains(":")) {
daemon = daemon + (testnet ? ":28081" : ":18081"); daemon = daemon + (testnet ? ":28081" : ":18081");
} }
intent.putExtra("daemon", daemon);
intent.putExtra("testnet", testnet); WalletManager.getInstance().setDaemon(daemon, testnet);
intent.putExtra("wallet", walletName); }
intent.putExtra("password", walletPassword);
void startWallet(String walletName, String walletPassword) {
Log.d(TAG, "startWallet()");
Intent intent = new Intent(getApplicationContext(), WalletActivity.class);
intent.putExtra(WalletActivity.REQUEST_ID, walletName);
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
startActivity(intent); startActivity(intent);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.layout; package com.m2049r.xmrwallet.layout;
import android.graphics.Color; import android.graphics.Color;
@@ -22,10 +38,10 @@ import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> { public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> {
static final String TAG = "TransactionInfoAdapter"; private static final String TAG = "TransactionInfoAdapter";
static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss"); private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss");
static final int TX_RED = Color.rgb(255, 79, 65); static final int TX_RED = Color.rgb(255, 79, 65);
static final int TX_GREEN = Color.rgb(54, 176, 91); static final int TX_GREEN = Color.rgb(54, 176, 91);
@@ -84,15 +100,15 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
notifyDataSetChanged(); notifyDataSetChanged();
} }
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView tvAmount; final TextView tvAmount;
public final TextView tvAmountPoint; final TextView tvAmountPoint;
public final TextView tvAmountDecimal; final TextView tvAmountDecimal;
public final TextView tvDate; final TextView tvDate;
public final TextView tvTime; final TextView tvTime;
public TransactionInfo infoItem; TransactionInfo infoItem;
public ViewHolder(View itemView) { ViewHolder(View itemView) {
super(itemView); super(itemView);
this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount); this.tvAmount = (TextView) itemView.findViewById(R.id.tx_amount);
// I know this is stupid but can't be bothered to align decimals otherwise // I know this is stupid but can't be bothered to align decimals otherwise

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.model; package com.m2049r.xmrwallet.model;
import java.util.List; import java.util.List;

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.model; package com.m2049r.xmrwallet.model;
public class TransactionInfo { public class TransactionInfo {
@@ -7,7 +23,7 @@ public class TransactionInfo {
public long handle; public long handle;
public TransactionInfo(long handle) { TransactionInfo(long handle) {
this.handle = handle; this.handle = handle;
} }

View File

@@ -1,7 +1,25 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.model; package com.m2049r.xmrwallet.model;
import android.util.Log; import android.util.Log;
import java.io.File;
public class Wallet { public class Wallet {
static { static {
System.loadLibrary("monerujo"); System.loadLibrary("monerujo");
@@ -9,10 +27,15 @@ public class Wallet {
static final String TAG = "Wallet"; static final String TAG = "Wallet";
public String getName() {
String p = getPath();
return new File(p).getName();
}
private long handle = 0; private long handle = 0;
private long listenerHandle = 0; private long listenerHandle = 0;
public Wallet(long handle) { Wallet(long handle) {
this.handle = handle; this.handle = handle;
} }
@@ -30,8 +53,6 @@ public class Wallet {
//public native long createWalletListenerJ(); //public native long createWalletListenerJ();
public native boolean close(); // from WalletManager
public native String getSeed(); public native String getSeed();
public native String getSeedLanguage(); public native String getSeedLanguage();
@@ -67,10 +88,19 @@ public class Wallet {
public native boolean store(String path); public native boolean store(String path);
public boolean close() {
return WalletManager.getInstance().close(this);
}
public native String getFilename(); public native String getFilename();
// virtual std::string keysFilename() const = 0; // virtual std::string keysFilename() const = 0;
public native boolean init(String daemon_address, long upper_transaction_size_limit); public boolean init(long upper_transaction_size_limit) {
return initJ(WalletManager.getInstance().getDaemonAddress(), upper_transaction_size_limit);
}
private native boolean initJ(String daemon_address, long upper_transaction_size_limit);
// virtual bool createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const = 0; // virtual bool createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const = 0;
// virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0; // virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0;
// virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0; // virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0;

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.model; package com.m2049r.xmrwallet.model;
public interface WalletListener { public interface WalletListener {

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.model; package com.m2049r.xmrwallet.model;
import android.util.Log; import android.util.Log;
@@ -8,10 +24,12 @@ import java.io.FileReader;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class WalletManager { public class WalletManager {
final static String TAG = "WalletManager"; private final static String TAG = "WalletManager";
static { static {
System.loadLibrary("monerujo"); System.loadLibrary("monerujo");
@@ -27,23 +45,57 @@ public class WalletManager {
return WalletManager.Instance; return WalletManager.Instance;
} }
public Wallet createWallet(String path, String password, String language, boolean isTestNet) { private WalletManager() {
long walletHandle = createWalletJ(path, password, language, isTestNet); this.managedWallets = new HashMap<>();
return new Wallet(walletHandle);
} }
public Wallet openWallet(String path, String password, boolean isTestNet) { private Map<String, Wallet> managedWallets;
long walletHandle = openWalletJ(path, password, isTestNet);
return new Wallet(walletHandle); public Wallet getWallet(String walletId) {
return managedWallets.get(walletId);
} }
public Wallet recoveryWallet(String path, String mnemonic, boolean isTestNet) { private void manageWallet(String walletId, Wallet wallet) {
return recoveryWallet(path, mnemonic, isTestNet, 0); if (getWallet(walletId) != null) {
throw new IllegalStateException("Wallet already under management!");
}
Log.d(TAG, "Managing " + walletId);
managedWallets.put(walletId, wallet);
} }
public Wallet recoveryWallet(String path, String mnemonic, boolean isTestNet, long restoreHeight) { private void unmanageWallet(String walletId) {
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet, restoreHeight); if (getWallet(walletId) == null) {
return new Wallet(walletHandle); throw new IllegalStateException("Wallet not under management!");
}
Log.d(TAG, "Unmanaging " + walletId);
managedWallets.remove(walletId);
}
public Wallet createWallet(String path, String password, String language) {
long walletHandle = createWalletJ(path, password, language, isTestNet());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
return wallet;
}
public Wallet openWallet(String path, String password) {
long walletHandle = openWalletJ(path, password, isTestNet());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
return wallet;
}
public Wallet recoveryWallet(String path, String mnemonic) {
Wallet wallet = recoveryWallet(path, mnemonic, 0);
manageWallet(wallet.getName(), wallet);
return wallet;
}
public Wallet recoveryWallet(String path, String mnemonic, long restoreHeight) {
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet(), restoreHeight);
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
return wallet;
} }
private native long createWalletJ(String path, String password, String language, boolean isTestNet); private native long createWalletJ(String path, String password, String language, boolean isTestNet);
@@ -59,6 +111,20 @@ public class WalletManager {
String viewKeyString, String viewKeyString,
String spendKeyString); String spendKeyString);
public native boolean closeJ(Wallet wallet);
public boolean close(Wallet wallet) {
String walletId = new File(wallet.getFilename()).getName();
unmanageWallet(walletId);
boolean closed = closeJ(wallet);
if (!closed) {
// in case we could not close it
// we unmanage it
manageWallet(walletId, wallet);
}
return closed;
}
public native boolean walletExists(String path); public native boolean walletExists(String path);
public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only); public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
@@ -85,7 +151,7 @@ public class WalletManager {
String filename = found[i].getName(); String filename = found[i].getName();
info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1 info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1
File addressFile = new File(path, info.name + ".address.txt"); File addressFile = new File(path, info.name + ".address.txt");
Log.d(TAG, addressFile.getAbsolutePath()); //Log.d(TAG, addressFile.getAbsolutePath());
info.address = "??????"; info.address = "??????";
BufferedReader addressReader = null; BufferedReader addressReader = null;
try { try {
@@ -111,20 +177,34 @@ public class WalletManager {
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0; //TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
String daemonAddress = null; private String daemonAddress = null;
private boolean testnet = true;
public void setDaemonAddress(String address) { public boolean isTestNet() {
if (daemonAddress == null) {
// assume testnet not explicitly initialised
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
}
return testnet;
}
public void setDaemon(String address, boolean testnet) {
this.daemonAddress = address; this.daemonAddress = address;
this.testnet = testnet;
setDaemonAddressJ(address); setDaemonAddressJ(address);
} }
public String getDaemonAddress() { public String getDaemonAddress() {
if (daemonAddress == null) {
// assume testnet not explicitly initialised
throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
}
return this.daemonAddress; return this.daemonAddress;
} }
private native void setDaemonAddressJ(String address); private native void setDaemonAddressJ(String address);
public native int getConnectedDaemonVersion(); public native int getDaemonVersion();
public native long getBlockchainHeight(); public native long getBlockchainHeight();

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.service;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
* The started Thread has a stck size of STACK_SIZE (=3MB)
*/
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

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.util; package com.m2049r.xmrwallet.util;
import android.Manifest; import android.Manifest;
@@ -12,8 +28,8 @@ import com.m2049r.xmrwallet.R;
import java.io.File; import java.io.File;
public class Helper { public class Helper {
static final String TAG = "Helper"; private static final String TAG = "Helper";
static final String WALLET_DIR = "Monerujo"; private static final String WALLET_DIR = "Monerujo";
static public File getStorageRoot(Context context) { static public File getStorageRoot(Context context) {
if (!isExternalStorageWritable()) { if (!isExternalStorageWritable()) {
@@ -54,11 +70,7 @@ public class Helper {
static public String getWalletPath(Context context, String aWalletName) { static public String getWalletPath(Context context, String aWalletName) {
File walletDir = getStorageRoot(context); File walletDir = getStorageRoot(context);
Log.d(TAG, "walletdir=" + walletDir.getAbsolutePath()); //d(TAG, "walletdir=" + walletDir.getAbsolutePath());
if (!walletDir.exists()) {
Log.d(TAG, "walletdir did not exist!");
walletDir.mkdirs();
}
File f = new File(walletDir, aWalletName); File f = new File(walletDir, aWalletName);
Log.d(TAG, "wallet = " + f.getAbsolutePath() + " size=" + f.length()); Log.d(TAG, "wallet = " + f.getAbsolutePath() + " size=" + f.length());
return f.getAbsolutePath(); return f.getAbsolutePath();
@@ -67,10 +79,7 @@ public class Helper {
/* Checks if external storage is available for read and write */ /* Checks if external storage is available for read and write */
static public boolean isExternalStorageWritable() { static public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState(); String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) { return Environment.MEDIA_MOUNTED.equals(state);
return true;
}
return false;
} }
} }

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