mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-06 19:00:30 +02:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e8b749af3b | ||
![]() |
f282f01edd | ||
![]() |
f16afdbb19 | ||
![]() |
ccacec9d0b | ||
![]() |
9ebacb8528 |
@@ -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 |
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
12
app/src/main/res/menu/wallet_details_menu.xml
Normal file
12
app/src/main/res/menu/wallet_details_menu.xml
Normal 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>
|
@@ -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>
|
||||
|
44
app/src/main/res/raw/help_details.html
Normal file
44
app/src/main/res/raw/help_details.html
Normal 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>
|
@@ -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
|
||||
|
Reference in New Issue
Block a user