Merge pull request #39 from m2049r/bugfix_issue_36

Use AsyncTask with 5MB stack in lots of places
This commit is contained in:
m2049r 2017-09-04 20:51:21 +02:00 committed by GitHub
commit 5b3e92e91a
6 changed files with 173 additions and 84 deletions

View File

@ -17,8 +17,10 @@
package com.m2049r.xmrwallet;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -28,15 +30,13 @@ import android.widget.TextView;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
import java.io.File;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
public class GenerateReviewFragment extends Fragment {
static final String TAG = "GenerateReviewFragment";
static final public String VIEW_DETAILS = "details";
static final public String VIEW_ACCEPT = "accept";
static final public String VIEW_WALLET = "wallet";
static final public String VIEW_TYPE_DETAILS = "details";
static final public String VIEW_TYPE_ACCEPT = "accept";
static final public String VIEW_TYPE_WALLET = "wallet";
ProgressBar pbProgress;
TextView tvWalletName;
@ -76,16 +76,12 @@ public class GenerateReviewFragment extends Fragment {
showProgress();
Bundle b = getArguments();
String type = b.getString("type");
if (!type.equals(VIEW_WALLET)) {
String path = b.getString("path");
String password = b.getString("password");
tvWalletName.setText(new File(path).getName());
show(path, password, type);
} else {
show(walletCallback.getWallet(), null, type);
}
Bundle args = getArguments();
String path = args.getString("path");
String password = args.getString("password");
String type = args.getString("type");
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
path, password, type);
return view;
}
@ -96,40 +92,64 @@ public class GenerateReviewFragment extends Fragment {
acceptCallback.onAccept(name, password);
}
private void show(final String walletPath, final String password, final String type) {
new Thread(null,
new Runnable() {
@Override
public void run() {
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
getActivity().runOnUiThread(new Runnable() {
public void run() {
show(wallet, password, type);
wallet.close();
}
});
}
}
, "DetailsReview", MoneroHandlerThread.THREAD_STACK_SIZE).start();
}
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
String type;
String password;
private void show(final Wallet wallet, final String password, final String type) {
if (type.equals(GenerateReviewFragment.VIEW_ACCEPT)) {
tvWalletPassword.setText(password);
bAccept.setVisibility(View.VISIBLE);
bAccept.setEnabled(true);
String name;
String address;
String seed;
String viewKey;
boolean isWatchOnly;
@Override
protected Boolean doInBackground(String... params) {
if (params.length != 3) return false;
String walletPath = params[0];
password = params[1];
type = params[2];
Wallet wallet;
boolean closeWallet;
if (type.equals(GenerateReviewFragment.VIEW_TYPE_WALLET)) {
wallet = GenerateReviewFragment.this.walletCallback.getWallet();
closeWallet = false;
} else {
wallet = WalletManager.getInstance().openWallet(walletPath, password);
closeWallet = true;
}
if (wallet.getStatus() != Wallet.Status.Status_Ok) return false;
name = wallet.getName();
address = wallet.getAddress();
seed = wallet.getSeed();
viewKey = wallet.getSecretViewKey();
isWatchOnly = wallet.isWatchOnly();
if (closeWallet) wallet.close();
return true;
}
tvWalletName.setText(wallet.getName());
tvWalletAddress.setText(wallet.getAddress());
tvWalletMnemonic.setText(wallet.getSeed());
tvWalletViewKey.setText(wallet.getSecretViewKey());
String spend = wallet.isWatchOnly() ? "" : "not available - use seed for recovery";
if (spend.length() > 0) { //TODO should be == 64, but spendkey is not in the API yet
tvWalletSpendKey.setText(spend);
} else {
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
if (type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT)) {
tvWalletPassword.setText(password);
bAccept.setVisibility(View.VISIBLE);
bAccept.setEnabled(true);
}
tvWalletName.setText(name);
tvWalletAddress.setText(address);
tvWalletMnemonic.setText(seed);
tvWalletViewKey.setText(viewKey);
String spend = isWatchOnly ? "" : "not available - use seed for recovery";
if (spend.length() > 0) { //TODO should be == 64, but spendkey is not in the API yet
tvWalletSpendKey.setText(spend);
} else {
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
}
}
hideProgress();
}
hideProgress();
}
GenerateReviewFragment.Listener acceptCallback = null;
@ -141,6 +161,7 @@ public class GenerateReviewFragment extends Fragment {
public interface ListenerWithWallet {
Wallet getWallet();
}
@Override

View File

@ -121,7 +121,7 @@ public class LoginActivity extends AppCompatActivity
promptPassword(walletName, new PasswordAction() {
@Override
public void action(String walletName, String password) {
startDetails(walletFile, password, GenerateReviewFragment.VIEW_DETAILS);
startDetails(walletFile, password, GenerateReviewFragment.VIEW_TYPE_DETAILS);
}
});
} else { // this cannot really happen as we prefilter choices
@ -646,6 +646,7 @@ public class LoginActivity extends AppCompatActivity
//////////////////////////////////////////
static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more
// TODO make this an AsyncTask?
public void createWallet(final String name, final String password, final WalletCreator walletCreator) {
final GenerateFragment genFragment = (GenerateFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
@ -666,7 +667,7 @@ public class LoginActivity extends AppCompatActivity
cacheFile.delete();
File keysFile = new File(newWalletFolder, name + ".keys");
keysFile.delete();
final File addressFile = new File(newWalletFolder, name + ".address.txt");
File addressFile = new File(newWalletFolder, name + ".address.txt");
addressFile.delete();
if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) {
@ -678,7 +679,7 @@ public class LoginActivity extends AppCompatActivity
File newWalletFile = new File(newWalletFolder, name);
boolean success = walletCreator.createWallet(newWalletFile, password);
if (success) {
startDetails(newWalletFile, password, GenerateReviewFragment.VIEW_ACCEPT);
startDetails(newWalletFile, password, GenerateReviewFragment.VIEW_TYPE_ACCEPT);
} else {
Toast.makeText(LoginActivity.this,
getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show();

View File

@ -18,6 +18,7 @@ package com.m2049r.xmrwallet;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
@ -34,6 +35,7 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
@ -43,8 +45,8 @@ import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import java.util.HashMap;
import java.util.Map;
@ -187,38 +189,50 @@ public class ReceiveFragment extends Fragment {
}
}
private void show(final String address) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
tvAddress.setText(address);
etPaymentId.setEnabled(true);
etAmount.setEnabled(true);
bPaymentId.setEnabled(true);
bGenerate.setEnabled(true);
hideProgress();
generateQr();
}
});
private void show(String address) {
tvAddress.setText(address);
etPaymentId.setEnabled(true);
etAmount.setEnabled(true);
bPaymentId.setEnabled(true);
bGenerate.setEnabled(true);
hideProgress();
generateQr();
}
private void show(final String walletPath, final String password) {
new Thread(null,
new Runnable() {
@Override
public void run() {
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
getActivity().runOnUiThread(new Runnable() {
public void run() {
String address = wallet.getAddress();
wallet.close();
show(address);
}
});
}
}
, "Receive", MoneroHandlerThread.THREAD_STACK_SIZE).start();
private void show(String walletPath, String password) {
new ReceiveFragment.AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
walletPath, password);
}
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
String password;
String address;
@Override
protected Boolean doInBackground(String... params) {
if (params.length != 2) return false;
String walletPath = params[0];
password = params[1];
Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
address = wallet.getAddress();
wallet.close();
return true;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
show(address);
} else {
Toast.makeText(getActivity(), getString(R.string.receive_cannot_open), Toast.LENGTH_LONG).show();
hideProgress();
}
}
}
private boolean amountOk() {
String amountEntry = etAmount.getText().toString();
if (amountEntry.isEmpty()) return true;

View File

@ -24,7 +24,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.UrlQuerySanitizer;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
@ -35,8 +34,6 @@ import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
@ -49,7 +46,6 @@ import com.m2049r.xmrwallet.util.BarcodeData;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.TxData;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@ -594,7 +590,7 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
Bundle extras = new Bundle();
extras.putString("type", GenerateReviewFragment.VIEW_WALLET);
extras.putString("type", GenerateReviewFragment.VIEW_TYPE_WALLET);
replaceFragment(new GenerateReviewFragment(), null, extras);
break;
case DialogInterface.BUTTON_NEGATIVE:

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.util;
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class MoneroThreadPoolExecutor {
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(null, r, "MoneroTask #" + mCount.getAndIncrement(), MoneroHandlerThread.THREAD_STACK_SIZE);
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<>(128);
public static final Executor MONERO_THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
MONERO_THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
}

View File

@ -177,6 +177,7 @@
<string name="receive_paymentid_hint">(optional)</string>
<string name="receive_amount_label">Amount</string>
<string name="receive_amount_hint">(optional)</string>
<string name="receive_cannot_open">Could not open wallet!</string>
<string name="details_alert_message">Sensitive data will now be shown.\nLook over your shoulder!</string>
<string name="details_alert_yes">I\'m safe</string>