Merge pull request #4 from m2049r/features

lots of tweaks
merge-requests/3/head
m2049r 7 years ago committed by GitHub
commit 046238a29f

@ -89,7 +89,6 @@
<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/builds" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/cmake" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />

@ -58,6 +58,10 @@ public class WalletActivity extends AppCompatActivity
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart()");
this.synced = false; // init syncing logic
}
private void startWalletService() {
acquireWakeLock();
Bundle extras = getIntent().getExtras();
if (extras != null) {
@ -67,6 +71,8 @@ public class WalletActivity extends AppCompatActivity
} else {
throw new IllegalStateException("No extras passed! Panic!");
}
onProgress(getString(R.string.status_wallet_loading));
showProgress();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@ -75,7 +81,11 @@ public class WalletActivity extends AppCompatActivity
onProgress(10); // look like we are working!
}
}, 250);
//Log.d(TAG, "onStart() done.");
}
private void stopWalletService() {
releaseWakeLock();
disconnectWalletService();
}
private String title = null;
@ -95,15 +105,13 @@ public class WalletActivity extends AppCompatActivity
@Override
protected void onStop() {
Log.d(TAG, "onStop()");
releaseWakeLock();
disconnectWalletService();
this.synced = false;
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(TAG, "onDestroy()");
stopWalletService();
super.onDestroy();
}
@ -129,6 +137,7 @@ public class WalletActivity extends AppCompatActivity
recyclerView.setAdapter(adapter);
setTitle(getString(R.string.status_wallet_loading));
startWalletService();
//Log.d(TAG, "onCreate() done.");
}
@ -136,33 +145,34 @@ public class WalletActivity extends AppCompatActivity
private boolean synced = false;
private void updateStatus(Wallet wallet) {
Log.d(TAG, "updateStatus()");
setActivityTitle(wallet);
final TextView balanceView = (TextView) findViewById(R.id.tvBalance);
final TextView unlockedView = (TextView) findViewById(R.id.tvUnlockedBalance);
final TextView syncProgressView = (TextView) findViewById(R.id.tvBlockHeightProgress);
final TextView connectionStatusView = (TextView) findViewById(R.id.tvConnectionStatus);
//Wallet wallet = getWallet();
balanceView.setText(Wallet.getDisplayAmount(wallet.getBalance()));
unlockedView.setText(Wallet.getDisplayAmount(wallet.getUnlockedBalance()));
String sync = "";
// TODO: getConnectionStatus() blocks as it tries to connect - this is bad in the UI thread!
if (wallet.getConnectionStatus() == Wallet.ConnectionStatus.ConnectionStatus_Connected) {
if (mBoundService == null) throw new IllegalStateException("WalletService not bound.");
Wallet.ConnectionStatus daemonConnected = mBoundService.getConnectionStatus();
if (daemonConnected == Wallet.ConnectionStatus.ConnectionStatus_Connected) {
long daemonHeight = mBoundService.getDaemonHeight();
if (!wallet.isSynchronized()) {
long n = wallet.getDaemonBlockChainHeight() - wallet.getBlockChainHeight();
long n = daemonHeight - wallet.getBlockChainHeight();
sync = n + " " + getString(R.string.status_remaining);
if (firstBlock == 0) {
firstBlock = wallet.getBlockChainHeight();
}
int x = 100 - Math.round(100f * n / (1f * wallet.getDaemonBlockChainHeight() - firstBlock));
//Log.d(TAG, n + "/" + (wallet.getDaemonBlockChainHeight() - firstBlock));
int x = 100 - Math.round(100f * n / (1f * daemonHeight - firstBlock));
onProgress(getString(R.string.status_syncing) + " " + sync);
if (x == 0) x = -1;
onProgress(x);
} else {
sync = getString(R.string.status_synced) + ": " + wallet.getBlockChainHeight();
if (!synced) {
hideProgress();
saveWallet(); // save ONLY on first sync
saveWallet(); // save on first sync
// the usual use case is:
// open the wallet, wait for sync, check balance, close app
// even if we wait for new transactions, they will be synced and saved next time
@ -174,7 +184,7 @@ public class WalletActivity extends AppCompatActivity
}
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
syncProgressView.setText(sync);
connectionStatusView.setText(net + " " + wallet.getConnectionStatus().toString().substring(17));
connectionStatusView.setText(net + " " + daemonConnected.toString().substring(17));
}
@Override
@ -364,7 +374,12 @@ public class WalletActivity extends AppCompatActivity
runOnUiThread(new Runnable() {
public void run() {
ProgressBar progress = (ProgressBar) findViewById(R.id.pbProgress);
progress.setProgress(n);
if (n >= 0) {
progress.setIndeterminate(false);
progress.setProgress(n);
} else {
progress.setIndeterminate(true);
}
}
});
}

@ -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;
}
}

@ -21,7 +21,6 @@ import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@ -29,6 +28,7 @@ import android.os.Process;
import android.util.Log;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.TransactionHistory;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletListener;
import com.m2049r.xmrwallet.model.WalletManager;
@ -97,15 +97,27 @@ public class WalletService extends Service {
}
long lastBlockTime = 0;
int lastTxCount = 0;
public void newBlock(long height) {
if (wallet == null) throw new IllegalStateException("No wallet!");
// don't flood with an update for every block ...
if (lastBlockTime < System.currentTimeMillis() - 2000) {
Log.d(TAG, "newBlock() @" + height + "with observer " + observer);
Log.d(TAG, "newBlock() @" + height + " with observer " + observer);
lastBlockTime = System.currentTimeMillis();
if (observer != null) {
observer.onRefreshed(wallet, false);
boolean fullRefresh = false;
updateDaemonState(wallet, wallet.isSynchronized() ? height : 0);
if (!wallet.isSynchronized()) {
// we want to see our transactions as they come in
wallet.getHistory().refresh();
int txCount = wallet.getHistory().getCount();
if (txCount > lastTxCount) {
lastTxCount = txCount;
fullRefresh = true;
}
}
observer.onRefreshed(wallet, fullRefresh);
}
}
}
@ -118,17 +130,61 @@ public class WalletService extends Service {
public void refreshed() {
if (wallet == null) throw new IllegalStateException("No wallet!");
Log.d(TAG, "refreshed() " + wallet.getBalance() + " sync=" + wallet.isSynchronized() + "with observer " + observer);
Log.d(TAG, "refreshed() " + wallet.getName() + " " + wallet.getBalance() + " sync=" + wallet.isSynchronized() + " with observer " + observer);
if (updated) {
if (observer != null) {
wallet.getHistory().refresh();
Log.d(TAG, "refreshed() A");
updateDaemonState(wallet, 0);
Log.d(TAG, "refreshed() B");
TransactionHistory history = wallet.getHistory();
Log.d(TAG, "refreshed() C " + history.getCount());
history.refresh();
Log.d(TAG, "refreshed() D " + history.getCount());
Log.d(TAG, "refreshed() E");
observer.onRefreshed(wallet, true);
Log.d(TAG, "refreshed() D");
updated = false;
}
}
}
}
private long lastDaemonStatusUpdate = 0;
private long daemonHeight = 0;
private Wallet.ConnectionStatus connectionStatus = Wallet.ConnectionStatus.ConnectionStatus_Disconnected;
private static final long STATUS_UPDATE_INTERVAL = 120000; // 120s (blocktime)
private void updateDaemonState(Wallet wallet, long height) {
long t = System.currentTimeMillis();
if (height > 0) { // if we get a height, we are connected
daemonHeight = height;
connectionStatus = Wallet.ConnectionStatus.ConnectionStatus_Connected;
lastDaemonStatusUpdate = t;
} else {
if (t - lastDaemonStatusUpdate > STATUS_UPDATE_INTERVAL) {
lastDaemonStatusUpdate = t;
// these calls really connect to the daemon - wasting time
daemonHeight = wallet.getDaemonBlockChainHeight();
if (daemonHeight > 0) {
// if we get a valid height, the obviously we are connected
connectionStatus = Wallet.ConnectionStatus.ConnectionStatus_Connected;
} else {
// TODO: or connectionStatus = wallet.getConnectionStatus(); ?
connectionStatus = Wallet.ConnectionStatus.ConnectionStatus_Disconnected;
}
}
}
//Log.d(TAG, "updated daemon status: " + daemonHeight + "/" + connectionStatus.toString());
}
public long getDaemonHeight() {
return this.daemonHeight;
}
public Wallet.ConnectionStatus getConnectionStatus() {
return this.connectionStatus;
}
/////////////////////////////////////////////
// communication back to client (activity) //
/////////////////////////////////////////////
@ -217,7 +273,7 @@ public class WalletService extends Service {
// We are using a HandlerThread and a Looper to avoid loading and closing
// concurrency
HandlerThread thread = new HandlerThread("WalletService",
MoneroHandlerThread thread = new MoneroHandlerThread("WalletService",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
@ -294,14 +350,13 @@ public class WalletService extends Service {
Wallet aWallet = loadWallet(walletName, walletPassword);
listener = new MyWalletListener(aWallet);
listener.start();
showProgress(95);
showProgress(100);
}
showProgress(getString(R.string.status_wallet_connecting));
showProgress(-1);
// if we try to refresh the history here we get occasional segfaults!
// doesnt matter since we update as soon as we get a new block anyway
Log.d(TAG, "start() done");
if (observer != null) {
Wallet myWallet = getWallet();
myWallet.getHistory().refresh();
observer.onRefreshed(myWallet, true);
}
}
public void stop() {
@ -309,8 +364,13 @@ public class WalletService extends Service {
setObserver(null); // in case it was not reset already
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");
listener.getWallet().close();
myWallet.close();
Log.d(TAG, "stop() closed");
listener = null;
}

@ -11,11 +11,12 @@
<string name="status_walletlist_loading">Loading Wallet List</string>
<string name="status_wallet_loading">Loading Wallet &#8230;</string>
<string name="status_wallet_unloading">Saving Wallet</string>
<string name="status_wallet_connecting">Connecting &#8230;</string>
<string name="prompt_password">Password for</string>
<string name="bad_password">Bad password!</string>
<string name="prompt_daemon_missing">Daemon address must be set!</string>
<string name="prompt_wrong_net">Daemon type does not fit to wallet!</string>
<string name="warn_daemon_unavailable">Warning: cannot reach daemon!</string>
<string name="warn_daemon_unavailable">Cannot connect to daemon!</string>
<string name="panic">Something\'s wrong!</string>
<string name="title_amount">Amount</string>

Loading…
Cancel
Save