1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-06 19:00:30 +02:00

Compare commits

..

5 Commits
v1.0 ... v1.0.2

Author SHA1 Message Date
m2049r
e8b749af3b Bugfix Service restart after OS kill (#96)
* single open wallet

* prevent WalletService & Activity from restarting
removed stray png
2017-10-03 22:45:03 +02:00
m2049r
f282f01edd wallet updateStatus only when added (#95) 2017-10-03 19:04:45 +02:00
KeeJef
f16afdbb19 Some spelling and grammar changes (#94) 2017-10-03 18:39:29 +02:00
m2049r
ccacec9d0b Added explicit info about keeping mnemonic seed safe (#92) 2017-09-30 09:17:47 +02:00
m2049r
9ebacb8528 corrected backups folder 2017-09-29 23:20:38 +02:00
12 changed files with 152 additions and 66 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 23
versionName "1.0"
versionCode 25
versionName "1.0.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -19,9 +19,12 @@ package com.m2049r.xmrwallet;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -214,4 +217,15 @@ public class GenerateReviewFragment extends Fragment {
boolean backOk() {
return !type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT);
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.wallet_details_menu, menu);
}
}

View File

@@ -973,6 +973,9 @@ public class LoginActivity extends AppCompatActivity
case R.id.action_create_help:
HelpFragment.displayHelp(getSupportFragmentManager(),R.raw.help_create);
return true;
case R.id.action_details_help:
HelpFragment.displayHelp(getSupportFragmentManager(),R.raw.help_details);
return true;
case R.id.action_lincense_info:
LicensesFragment.displayLicensesFragment(getSupportFragmentManager());
return true;

View File

@@ -151,7 +151,10 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
// we don't store anything ourselves
// activity restarted
// we don't want that - finish it and fall back to previous activity
finish();
return;
}
setContentView(R.layout.wallet_activity);

View File

@@ -186,6 +186,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
private String walletTitle = null;
private void updateStatus(Wallet wallet) {
if (!isAdded()) return;
Log.d(TAG, "updateStatus()");
if (walletTitle == null) {
walletTitle = setActivityTitle(wallet);

View File

@@ -16,6 +16,7 @@
package com.m2049r.xmrwallet.model;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.BufferedReader;
@@ -45,36 +46,36 @@ public class WalletManager {
return WalletManager.Instance;
}
private WalletManager() {
this.managedWallets = new HashMap<>();
//private Map<String, Wallet> managedWallets;
private Wallet managedWallet = null;
public Wallet getWallet() {
return managedWallet;
}
private Map<String, Wallet> managedWallets;
public Wallet getWallet(String walletId) {
return managedWallets.get(walletId);
private void manageWallet(Wallet wallet) {
Log.d(TAG, "Managing " + wallet.getName());
managedWallet = wallet;
}
private void manageWallet(String walletId, Wallet wallet) {
if (getWallet(walletId) != null) {
throw new IllegalStateException(walletId + " already under management!");
private void unmanageWallet(Wallet wallet) {
if (wallet == null) {
throw new IllegalArgumentException("Cannot unmanage null!");
}
Log.d(TAG, "Managing " + walletId);
managedWallets.put(walletId, wallet);
}
private void unmanageWallet(String walletId) {
if (getWallet(walletId) == null) {
throw new IllegalStateException(walletId + " not under management!");
if (getWallet() == null) {
throw new IllegalStateException("No wallet under management!");
}
Log.d(TAG, "Unmanaging " + walletId);
managedWallets.remove(walletId);
if (getWallet() != wallet) {
throw new IllegalStateException(wallet.getName() + " not under management!");
}
Log.d(TAG, "Unmanaging " + managedWallet.getName());
managedWallet = null;
}
public Wallet createWallet(File aFile, String password, String language) {
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, isTestNet());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
manageWallet(wallet);
return wallet;
}
@@ -83,7 +84,7 @@ public class WalletManager {
public Wallet openWallet(String path, String password) {
long walletHandle = openWalletJ(path, password, isTestNet());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
manageWallet(wallet);
return wallet;
}
@@ -91,14 +92,14 @@ public class WalletManager {
public Wallet recoveryWallet(File aFile, String mnemonic) {
Wallet wallet = recoveryWallet(aFile, mnemonic, 0);
manageWallet(wallet.getName(), wallet);
manageWallet(wallet);
return wallet;
}
public Wallet recoveryWallet(File aFile, String mnemonic, long restoreHeight) {
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), mnemonic, isTestNet(), restoreHeight);
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
manageWallet(wallet);
return wallet;
}
@@ -109,7 +110,7 @@ public class WalletManager {
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), language, isTestNet(), restoreHeight,
addressString, viewKeyString, spendKeyString);
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet.getName(), wallet);
manageWallet(wallet);
return wallet;
}
@@ -123,13 +124,12 @@ public class WalletManager {
public native boolean closeJ(Wallet wallet);
public boolean close(Wallet wallet) {
String walletId = new File(wallet.getFilename()).getName();
unmanageWallet(walletId);
unmanageWallet(wallet);
boolean closed = closeJ(wallet);
if (!closed) {
// in case we could not close it
// we unmanage it
manageWallet(walletId, wallet);
// we manage it again
manageWallet(wallet);
}
return closed;
}

View File

@@ -70,20 +70,11 @@ public class WalletService extends Service {
private MyWalletListener listener = null;
private class MyWalletListener implements WalletListener {
private Wallet wallet;
boolean updated = true;
Wallet getWallet() {
return wallet;
}
MyWalletListener(Wallet aWallet) {
if (aWallet == null) throw new IllegalArgumentException("Cannot open wallet!");
this.wallet = aWallet;
}
void start() {
Log.d(TAG, "MyWalletListener.start()");
Wallet wallet = getWallet();
if (wallet == null) throw new IllegalStateException("No wallet!");
//acquireWakeLock();
wallet.setListener(this);
@@ -92,6 +83,7 @@ public class WalletService extends Service {
void stop() {
Log.d(TAG, "MyWalletListener.stop()");
Wallet wallet = getWallet();
if (wallet == null) throw new IllegalStateException("No wallet!");
wallet.pauseRefresh();
wallet.setListener(null);
@@ -115,6 +107,7 @@ public class WalletService extends Service {
int lastTxCount = 0;
public void newBlock(long height) {
Wallet wallet = getWallet();
if (wallet == null) throw new IllegalStateException("No wallet!");
// don't flood with an update for every block ...
if (lastBlockTime < System.currentTimeMillis() - 2000) {
@@ -141,14 +134,16 @@ public class WalletService extends Service {
}
public void updated() {
Log.d(TAG, "updated() " + wallet.getBalance());
Log.d(TAG, "updated()");
Wallet wallet = getWallet();
if (wallet == null) throw new IllegalStateException("No wallet!");
updated = true;
}
public void refreshed() {
Log.d(TAG, "refreshed()");
Wallet wallet = getWallet();
if (wallet == null) throw new IllegalStateException("No wallet!");
Log.d(TAG, "refreshed() " + wallet.getName() + " " + wallet.getBalance() + " sync=" + wallet.isSynchronized() + " with observer " + observer);
if (updated) {
if (observer != null) {
updateDaemonState(wallet, 0);
@@ -253,8 +248,7 @@ public class WalletService extends Service {
//
public Wallet getWallet() {
if (listener == null) throw new IllegalStateException("no listener");
return listener.getWallet();
return WalletManager.getInstance().getWallet();
}
/////////////////////////////////////////////
@@ -441,10 +435,15 @@ public class WalletService extends Service {
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg2 = START_SERVICE;
msg.setData(intent.getExtras());
mServiceHandler.sendMessage(msg);
//Log.d(TAG, "onStartCommand() message sent");
return START_STICKY;
if (intent != null) {
msg.setData(intent.getExtras());
mServiceHandler.sendMessage(msg);
return START_STICKY;
} else {
// process restart - don't do anything - let system kill it again
stop();
return START_NOT_STICKY;
}
}
@Override
@@ -466,9 +465,8 @@ public class WalletService extends Service {
}
private boolean start(String walletName, String walletPassword) {
startNotfication();
// if there is an listener it is always started / syncing
Log.d(TAG, "start()");
startNotfication();
showProgress(getString(R.string.status_wallet_loading));
showProgress(10);
if (listener == null) {
@@ -478,7 +476,7 @@ public class WalletService extends Service {
if (aWallet != null) aWallet.close();
return false;
}
listener = new MyWalletListener(aWallet);
listener = new MyWalletListener();
listener.start();
showProgress(100);
}
@@ -496,10 +494,6 @@ public class WalletService extends Service {
if (listener != null) {
listener.stop();
Wallet myWallet = getWallet();
// if (!myWallet.isSynchronized()) { // save only if NOT synced (to continue later)
// Log.d(TAG, "stop() saving");
// myWallet.store();
// }
Log.d(TAG, "stop() closing");
myWallet.close();
Log.d(TAG, "stop() closed");
@@ -561,6 +555,5 @@ public class WalletService extends Service {
.setContentIntent(pendingIntent)
.build();
startForeground(NOTIFICATION_ID, notification);
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_details_help"
android:icon="@drawable/ic_help_black_24dp"
android:orderInCategory="100"
android:title="@string/menu_help"
app:showAsAction="always" />
</menu>

View File

@@ -12,26 +12,42 @@ A wallet can be created in a number of ways:
<li>View Only</li>
</ul>
In all cases you need to name your wallet and give it a password. The password is used for
securing your wallet data on the device. Use a strong password - better a passphrase.
securing your wallet data on the device. Use a strong password - even better use a passphrase.
<h2>New Address</h2>
You need a new Monero Address.<br/>
No need to enter additional info.
You need a new Monero Address - no need to enter any additional info.
<h3>Take Note of your Mnemonic Seed!</h3>
<p>
On the following screen you will find your 25-word "Mnemonic Seed".
This is the only data needed to recover your wallet at a later point
and gain full access to your funds.
Keeping this secure and private is very important, as it gives <em>anyone</em>
full access to your funds!
</p>
<p>
If you lose your wallet password, you can still recover your wallet with the Mnemonic Seed.
</p>
<p>
There is no way to recover your Mnemonic Seed, if you lose it all your funds will be lost!
The Mnemonic Seed can also never be changed, and if it is stolen or otherwise compromised,
you will have to move your funds to new wallet (with a new Mnemonic Seed). Therefore, it is best
that you backup your Mnemonic Seed by writing it down and storing it in <em>multiple</em> safe
and secure places.
</p>
<h2>Recover from Seed</h2>
You already have a Monero Address and want to recover the transactions from the blockchain.<br/>
If you already have a Monero Address and want to recover the transactions from the blockchain.<br/>
Enter your Seed in the field "Mnemonic Seed". If you know the block number of the first
transaction used for this address, enter it in the field "Restore Height" - leaving in blank will
transaction used for this address, enter it in the field "Restore Height" - leaving it blank will
scan the <em>entire</em> blockchain for transactions belonging to your address.
This takes a <em>long</em> time.
<h2>Recover from Keys</h2>
Instead of recovering from the mnemonic seed, you can recover using your keys.<br/>
Instead of recovering from the Mnemonic Seed, you can recover using your keys.<br/>
Enter your Monero Address in the field "Public Address" and fill out "View Key", "Spend Key"
and optionally "Restore Height" with the appropriate values.
<h2>View Only</h2>
You just want to monitor incoming transactions to a wallet.<br/>
If you just want to monitor incoming transactions to a wallet.<br/>
Enter your Monero Address in the field "Public Address" and fill out the "View Key" and
optionally "Restore Height" with the appropriate values leaving the "Spend Key" blank.
</body>

View File

@@ -0,0 +1,44 @@
<html>
<head>
<style>body {font-family: sans-serif; font-size: 1em;}</style>
</head>
<body>
<h1>Wallet Details</h1>
Here you see the details of your wallet.
<ul>
<li>Mnemonic Seed</li>
<li>Public Address</li>
<li>View Key</li>
<li>Spend Key</li>
</ul>
<h2>Mnemonic Seed</h2>
<p>
Your 25-word "Mnemonic Seed". This is the only data needed to recover your wallet at a later
point and gain full access to your funds.
Keeping this secure and private is very important, as it gives <em>anyone</em>
full access to your funds!
</p>
<p>
If you lose your wallet password, you can still recover your wallet with the Mnemonic Seed.
</p>
<p>
There is no way to recover your Mnemonic Seed, if you lose it all your funds will be lost!
The Mnemonic Seed can also never be changed, and if it is stolen or otherwise compromised,
you will have to move your funds to new wallet (with a new Mnemonic Seed). Therefore, it is best
that you backup your Mnemonic Seed by writing it down and storing it in <em>multiple</em> safe
and secure places.
</p>
<h2>Public Address</h2>
This is your account number. You use it to receive funds. A sender needs to know nothing
more than this address to send you Monero.
<h2>View Key</h2>
This key is required for creating a view-only wallet or for recovering from keys.
<h2>Spend Key</h2>
This is key is required for recovering from keys.
</body>
</html>

View File

@@ -22,7 +22,7 @@
- All significant figures shown in balance
- QR Code scanning - make sure to *ALWAYS* verify the scanned code is what it is advertised to be!
- QR Code for receiving with conversion of XMR to USD/EUR and back through kraken API
- Backup wallets to ```.backups``` folder in main wallet folder (old backups are overwritten)
- Backup wallets to ```backups``` folder in main wallet folder (old backups are overwritten)
- Rename wallets
- Archive (=Backup and delete)
- 3 Default nodes + History of last 5 used nodes