mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-04 17:28:42 +02:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
093e4bda1d | ||
![]() |
4aa7000cb3 | ||
![]() |
62844192df | ||
![]() |
855b35a6b7 | ||
![]() |
88110b702f | ||
![]() |
0013caa05f | ||
![]() |
5b3e92e91a | ||
![]() |
f8ea3cc77f | ||
![]() |
59ef2a1f8e | ||
![]() |
fae07ed716 | ||
![]() |
e662d5a9c0 | ||
![]() |
4b2d52fbe6 | ||
![]() |
ec7798cb34 | ||
![]() |
20e7d6d065 | ||
![]() |
89ada5b294 | ||
![]() |
fe80fef36e | ||
![]() |
e8331dda7a | ||
![]() |
68abaec6cb | ||
![]() |
fe84bae9ed | ||
![]() |
1289a0ada4 | ||
![]() |
93025c5e1b | ||
![]() |
e0439a1359 | ||
![]() |
93ec3865da | ||
![]() |
49e338e80d | ||
![]() |
075ddff226 | ||
![]() |
7eaf17d48e | ||
![]() |
6822aa83d8 | ||
![]() |
20dbaac4fa | ||
![]() |
726887af2e | ||
![]() |
03da2880ac | ||
![]() |
78c053f4e8 |
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@@ -1,2 +1,2 @@
|
||||
workspace.xml
|
||||
markdown-navigator*
|
||||
markdown-*
|
||||
|
@@ -21,7 +21,6 @@ You may loose all your Moneroj if you use this App. Be cautious when spending on
|
||||
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
|
||||
|
||||
### TODO
|
||||
- wallet backup functions
|
||||
- review visibility of methods/classes
|
||||
- more sensible error dialogs
|
||||
- check licenses of included libraries; License Dialog
|
||||
|
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 8
|
||||
versionName "0.5.1"
|
||||
versionCode 11
|
||||
versionName "0.6"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:icon="@drawable/ic_monero_32dp"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
@@ -461,7 +461,6 @@ Java_com_m2049r_xmrwallet_model_WalletManager_resolveOpenAlias(JNIEnv *env, jobj
|
||||
|
||||
//TODO static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
|
||||
|
||||
// actually a WalletManager function, but logically in onWalletSelected
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
|
||||
jobject walletInstance) {
|
||||
|
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextWatcher;
|
||||
@@ -69,12 +69,9 @@ public class GenerateFragment extends Fragment {
|
||||
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
||||
|
||||
etWalletMnemonic.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etWalletAddress.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etWalletViewKey.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etWalletSpendKey.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||
//etWalletMnemonic.setTextIsSelectable(testnet);
|
||||
etWalletAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletViewKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etWalletSpendKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
|
||||
Helper.showKeyboard(getActivity());
|
||||
etWalletName.addTextChangedListener(new TextWatcher() {
|
||||
@@ -298,8 +295,12 @@ public class GenerateFragment extends Fragment {
|
||||
private void generateWallet() {
|
||||
String name = etWalletName.getText().toString();
|
||||
if (name.length() == 0) return;
|
||||
String walletPath = Helper.getWalletPath(getActivity(), name);
|
||||
if (WalletManager.getInstance().walletExists(walletPath)) {
|
||||
if (name.charAt(0)=='.') {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_wallet_dot), Toast.LENGTH_LONG).show();
|
||||
etWalletName.requestFocus();
|
||||
}
|
||||
File walletFile = Helper.getWalletFile(getActivity(), name);
|
||||
if (WalletManager.getInstance().walletExists(walletFile)) {
|
||||
Toast.makeText(getActivity(), getString(R.string.generate_wallet_exists), Toast.LENGTH_LONG).show();
|
||||
etWalletName.requestFocus();
|
||||
return;
|
||||
@@ -348,7 +349,7 @@ public class GenerateFragment extends Fragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onPause()");
|
||||
Log.d(TAG, "onResume()");
|
||||
activityCallback.setTitle(getString(R.string.generate_title));
|
||||
}
|
||||
|
||||
|
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
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 name = b.getString("name");
|
||||
String password = b.getString("password");
|
||||
tvWalletName.setText(new File(name).getName());
|
||||
show(name, 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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,12 +16,13 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.KeyEvent;
|
||||
@@ -82,9 +83,17 @@ public class LoginFragment extends Fragment {
|
||||
|
||||
File getStorageRoot();
|
||||
|
||||
void onWalletSelected(final String wallet);
|
||||
void onWalletSelected(String wallet);
|
||||
|
||||
void onWalletDetails(final String wallet);
|
||||
void onWalletDetails(String wallet);
|
||||
|
||||
void onWalletReceive(String wallet);
|
||||
|
||||
void onWalletRename(String name);
|
||||
|
||||
void onWalletBackup(String name);
|
||||
|
||||
void onWalletArchive(String walletName);
|
||||
|
||||
void onAddWallet();
|
||||
|
||||
@@ -117,14 +126,14 @@ public class LoginFragment extends Fragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onPause()");
|
||||
Log.d(TAG, "onResume()");
|
||||
activityCallback.setTitle(getString(R.string.login_activity_name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
Log.d(TAG, "onCreateView");
|
||||
View view = inflater.inflate(R.layout.login_fragment, container, false);
|
||||
|
||||
tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet);
|
||||
@@ -222,31 +231,6 @@ public class LoginFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
/* listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Difference to opening wallet is that we don't need a daemon set
|
||||
String itemValue = (String) listView.getItemAtPosition(position);
|
||||
|
||||
if (itemValue.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
|
||||
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH);
|
||||
String x = isMainNet() ? "4" : "9A";
|
||||
if (x.indexOf(itemValue.charAt(1)) < 0) {
|
||||
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
||||
|
||||
activityCallback.onWalletDetails(wallet);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
*/
|
||||
loadList();
|
||||
return view;
|
||||
}
|
||||
@@ -260,7 +244,8 @@ public class LoginFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadList() {
|
||||
public void loadList() {
|
||||
Log.d(TAG, "loadList()");
|
||||
WalletManager mgr = WalletManager.getInstance();
|
||||
List<WalletManager.WalletInfo> walletInfos =
|
||||
mgr.findWallets(activityCallback.getStorageRoot());
|
||||
@@ -408,32 +393,52 @@ public class LoginFragment extends Fragment {
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
String listItem = (String) listView.getItemAtPosition(info.position);
|
||||
String name = nameFromListItem(listItem, !isMainNet());
|
||||
if (name == null) {
|
||||
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_info:
|
||||
String listItem = (String) listView.getItemAtPosition(info.position);
|
||||
return showInfo(listItem);
|
||||
showInfo(name);
|
||||
break;
|
||||
case R.id.action_receive:
|
||||
showReceive(name);
|
||||
break;
|
||||
case R.id.action_rename:
|
||||
activityCallback.onWalletRename(name);
|
||||
break;
|
||||
case R.id.action_backup:
|
||||
activityCallback.onWalletBackup(name);
|
||||
break;
|
||||
case R.id.action_archive:
|
||||
activityCallback.onWalletArchive(name);
|
||||
break;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean showInfo(String listItem) {
|
||||
|
||||
if (listItem.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
|
||||
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH);
|
||||
String x = isMainNet() ? "4" : "9A";
|
||||
if (x.indexOf(listItem.charAt(1)) < 0) {
|
||||
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
||||
|
||||
activityCallback.onWalletDetails(wallet);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showInfo(@NonNull String name) {
|
||||
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
||||
|
||||
activityCallback.onWalletDetails(name);
|
||||
}
|
||||
|
||||
private boolean showReceive(@NonNull String name) {
|
||||
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
||||
|
||||
activityCallback.onWalletReceive(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
private String nameFromListItem(String listItem, boolean testnet) {
|
||||
String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH);
|
||||
String x = testnet ? "9A" : "4";
|
||||
if (x.indexOf(listItem.charAt(1)) < 0) {
|
||||
return null;
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
349
app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java
Normal file
349
app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -16,10 +16,10 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -28,8 +28,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.BarcodeData;
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
|
||||
@@ -39,9 +38,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
Listener activityCallback;
|
||||
|
||||
public interface Listener {
|
||||
void onAddressScanned(String address, String paymentId);
|
||||
|
||||
boolean isPaymentIdValid(String paymentId);
|
||||
boolean onAddressScanned(String uri);
|
||||
}
|
||||
|
||||
private ZXingScannerView mScannerView;
|
||||
@@ -61,32 +58,16 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
mScannerView.startCamera();
|
||||
}
|
||||
|
||||
static final String URI_PREFIX = "monero:";
|
||||
static final String PAYMENTID_STRING = "?tx_payment_id=";
|
||||
static final String QR_SCHEME = "monero:";
|
||||
static final String QR_PAYMENTID = "tx_payment_id";
|
||||
static final String QR_AMOUNT = "tx_amount";
|
||||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText());
|
||||
String text = rawResult.getText();
|
||||
//Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText());
|
||||
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
|
||||
(text.startsWith(URI_PREFIX))) {
|
||||
String address = null;
|
||||
String paymentId = null;
|
||||
String s = text.substring(URI_PREFIX.length());
|
||||
if (s.length() == 95) {
|
||||
address = s;
|
||||
} else {
|
||||
int i = s.indexOf(PAYMENTID_STRING);
|
||||
if ((i == 95) && (s.length() == (95 + PAYMENTID_STRING.length() + 16))) {
|
||||
address = s.substring(0, 95);
|
||||
paymentId = s.substring(95 + PAYMENTID_STRING.length());
|
||||
if (!activityCallback.isPaymentIdValid(paymentId)) {
|
||||
address = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Helper.isAddressOk(address, WalletManager.getInstance().isTestNet())) {
|
||||
activityCallback.onAddressScanned(address, paymentId);
|
||||
(rawResult.getText().startsWith(QR_SCHEME))) {
|
||||
if (activityCallback.onAddressScanned(rawResult.getText())) {
|
||||
return;
|
||||
} else {
|
||||
Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show();
|
||||
@@ -120,7 +101,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
Log.d(TAG, "attaching scan");
|
||||
//Log.d(TAG, "attaching scan");
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
} else {
|
||||
|
@@ -16,11 +16,11 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
@@ -51,7 +51,7 @@ public class SendFragment extends Fragment {
|
||||
EditText etAddress;
|
||||
EditText etPaymentId;
|
||||
EditText etAmount;
|
||||
Button bAddress;
|
||||
Button bScan;
|
||||
Button bSweep;
|
||||
Spinner sMixin;
|
||||
Spinner sPriority;
|
||||
@@ -84,7 +84,7 @@ public class SendFragment extends Fragment {
|
||||
etAddress = (EditText) view.findViewById(R.id.etAddress);
|
||||
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
|
||||
etAmount = (EditText) view.findViewById(R.id.etAmount);
|
||||
bAddress = (Button) view.findViewById(R.id.bAddress);
|
||||
bScan = (Button) view.findViewById(R.id.bScan);
|
||||
bSweep = (Button) view.findViewById(R.id.bSweep);
|
||||
bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend);
|
||||
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
|
||||
@@ -100,8 +100,8 @@ public class SendFragment extends Fragment {
|
||||
|
||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||
|
||||
etAddress.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etPaymentId.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
etAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
Helper.showKeyboard(getActivity());
|
||||
@@ -199,7 +199,7 @@ public class SendFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
bAddress.setOnClickListener(new View.OnClickListener() {
|
||||
bScan.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
activityCallback.onScanAddress();
|
||||
@@ -209,7 +209,8 @@ public class SendFragment extends Fragment {
|
||||
bPaymentId.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
etPaymentId.setText((activityCallback.generatePaymentId()));
|
||||
etPaymentId.setText((Wallet.generatePaymentId()));
|
||||
etPaymentId.setSelection(etPaymentId.getText().length());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -285,7 +286,7 @@ public class SendFragment extends Fragment {
|
||||
|
||||
private boolean paymentIdOk() {
|
||||
String paymentId = etPaymentId.getText().toString();
|
||||
return paymentId.isEmpty() || activityCallback.isPaymentIdValid(paymentId);
|
||||
return paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||
}
|
||||
|
||||
private void prepareSend() {
|
||||
@@ -321,6 +322,7 @@ public class SendFragment extends Fragment {
|
||||
etAddress.setEnabled(false);
|
||||
etPaymentId.setEnabled(false);
|
||||
etAmount.setEnabled(false);
|
||||
bScan.setEnabled(false);
|
||||
bPaymentId.setEnabled(false);
|
||||
bSweep.setEnabled(false);
|
||||
bPrepareSend.setEnabled(false);
|
||||
@@ -332,6 +334,7 @@ public class SendFragment extends Fragment {
|
||||
etAddress.setEnabled(true);
|
||||
etPaymentId.setEnabled(true);
|
||||
etAmount.setEnabled(true);
|
||||
bScan.setEnabled(true);
|
||||
bPaymentId.setEnabled(true);
|
||||
bSweep.setEnabled(true);
|
||||
bPrepareSend.setEnabled(true);
|
||||
@@ -356,10 +359,6 @@ public class SendFragment extends Fragment {
|
||||
|
||||
void onSend(String notes);
|
||||
|
||||
String generatePaymentId();
|
||||
|
||||
boolean isPaymentIdValid(String paymentId);
|
||||
|
||||
String getWalletAddress();
|
||||
|
||||
void onDisposeRequest();
|
||||
@@ -373,26 +372,40 @@ public class SendFragment extends Fragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume");
|
||||
BarcodeData data = activityCallback.getScannedData();
|
||||
if (data != null) {
|
||||
String scannedAddress = data.address;
|
||||
if (scannedAddress != null) {
|
||||
etAddress.setText(scannedAddress);
|
||||
} else {
|
||||
etAddress.getText().clear();
|
||||
}
|
||||
String scannedPaymenId = data.paymentId;
|
||||
if (scannedPaymenId != null) {
|
||||
etPaymentId.setText(scannedPaymenId);
|
||||
} else {
|
||||
etPaymentId.getText().clear();
|
||||
}
|
||||
if (data.amount >= 0) {
|
||||
String scannedAmount = Helper.getDisplayAmount(data.amount);
|
||||
etAmount.setText(scannedAmount);
|
||||
} else {
|
||||
etAmount.getText().clear();
|
||||
}
|
||||
etAmount.requestFocus();
|
||||
etAmount.setSelection(etAmount.getText().length());
|
||||
} else { // no scan data
|
||||
// jump to first empty field
|
||||
if (etAddress.getText().toString().isEmpty()) {
|
||||
etAddress.requestFocus();
|
||||
} else if (etPaymentId.getText().toString().isEmpty()) {
|
||||
etPaymentId.requestFocus();
|
||||
} else {
|
||||
etAmount.requestFocus();
|
||||
etAmount.setSelection(etAmount.getText().length());
|
||||
}
|
||||
}
|
||||
// jump to first empty field
|
||||
if (etAddress.getText().toString().isEmpty()) {
|
||||
etAddress.requestFocus();
|
||||
} else if (etPaymentId.getText().toString().isEmpty()) {
|
||||
etPaymentId.requestFocus();
|
||||
} else {
|
||||
etAmount.requestFocus();
|
||||
}
|
||||
Log.d(TAG, "onResume");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -16,28 +16,23 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,21 +16,20 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.constraint.ConstraintLayout;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
@@ -38,9 +37,8 @@ import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.List;
|
||||
@@ -59,6 +57,19 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
||||
ProgressBar pbProgress;
|
||||
Button bSend;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
if (activityCallback.hasWallet())
|
||||
inflater.inflate(R.menu.wallet_menu, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
@@ -69,9 +80,9 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
||||
clProgress = (ConstraintLayout) view.findViewById(R.id.clProgress);
|
||||
llUnconfirmedAmount = (LinearLayout) view.findViewById(R.id.llUnconfirmedAmount);
|
||||
tvBalance = (TextView) view.findViewById(R.id.tvBalance);
|
||||
tvBalance.setText(getDisplayAmount(0));
|
||||
tvBalance.setText(Helper.getDisplayAmount(0));
|
||||
tvUnconfirmedAmount = (TextView) view.findViewById(R.id.tvUnconfirmedAmount);
|
||||
tvUnconfirmedAmount.setText(getDisplayAmount(0));
|
||||
tvUnconfirmedAmount.setText(Helper.getDisplayAmount(0));
|
||||
tvBlockHeightProgress = (TextView) view.findViewById(R.id.tvBlockHeightProgress);
|
||||
|
||||
bSend = (Button) view.findViewById(R.id.bSend);
|
||||
@@ -175,23 +186,6 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
||||
private long firstBlock = 0;
|
||||
private String walletTitle = null;
|
||||
|
||||
private String getDisplayAmount(long amount) {
|
||||
String s = Wallet.getDisplayAmount(amount);
|
||||
int lastZero = 0;
|
||||
int decimal = 0;
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
if ((lastZero == 0) && (s.charAt(i) != '0')) lastZero = i + 1;
|
||||
// TODO i18n
|
||||
if (s.charAt(i) == '.') {
|
||||
decimal = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Log.d(TAG, decimal + "/" + lastZero + "/" + s);
|
||||
int cutoff = Math.max(lastZero, decimal + 2);
|
||||
return s.substring(0, cutoff);
|
||||
}
|
||||
|
||||
private void updateStatus(Wallet wallet) {
|
||||
Log.d(TAG, "updateStatus()");
|
||||
if (walletTitle == null) {
|
||||
@@ -200,8 +194,8 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
||||
}
|
||||
long balance = wallet.getBalance();
|
||||
long unlockedBalance = wallet.getUnlockedBalance();
|
||||
tvBalance.setText(getDisplayAmount(unlockedBalance));
|
||||
tvUnconfirmedAmount.setText(getDisplayAmount(balance - unlockedBalance));
|
||||
tvBalance.setText(Helper.getDisplayAmount(unlockedBalance));
|
||||
tvUnconfirmedAmount.setText(Helper.getDisplayAmount(balance - unlockedBalance));
|
||||
// balance cannot be less than unlockedBalance
|
||||
/*if (balance != unlockedBalance) {
|
||||
llPendingAmount.setVisibility(View.VISIBLE);
|
||||
@@ -259,6 +253,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
||||
boolean isWatchOnly();
|
||||
|
||||
String getTxKey(String txId);
|
||||
|
||||
void onWalletReceive();
|
||||
|
||||
boolean hasWallet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -238,6 +238,7 @@ public class Wallet {
|
||||
public native void setDefaultMixin(int mixin);
|
||||
|
||||
public native boolean setUserNote(String txid, String note);
|
||||
|
||||
public native String getUserNote(String txid);
|
||||
|
||||
public native String getTxKey(String txid);
|
||||
|
@@ -71,8 +71,8 @@ public class WalletManager {
|
||||
managedWallets.remove(walletId);
|
||||
}
|
||||
|
||||
public Wallet createWallet(String path, String password, String language) {
|
||||
long walletHandle = createWalletJ(path, password, language, isTestNet());
|
||||
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);
|
||||
return wallet;
|
||||
@@ -89,14 +89,14 @@ public class WalletManager {
|
||||
|
||||
private native long openWalletJ(String path, String password, boolean isTestNet);
|
||||
|
||||
public Wallet recoveryWallet(String path, String mnemonic) {
|
||||
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
||||
public Wallet recoveryWallet(File aFile, String mnemonic) {
|
||||
Wallet wallet = recoveryWallet(aFile, mnemonic, 0);
|
||||
manageWallet(wallet.getName(), wallet);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
public Wallet recoveryWallet(String path, String mnemonic, long restoreHeight) {
|
||||
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet(), restoreHeight);
|
||||
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);
|
||||
return wallet;
|
||||
@@ -104,9 +104,9 @@ public class WalletManager {
|
||||
|
||||
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
||||
|
||||
public Wallet createWalletFromKeys(String path, String language, long restoreHeight,
|
||||
public Wallet createWalletFromKeys(File aFile, String language, long restoreHeight,
|
||||
String addressString, String viewKeyString, String spendKeyString) {
|
||||
long walletHandle = createWalletFromKeysJ(path, language, isTestNet(), restoreHeight,
|
||||
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), language, isTestNet(), restoreHeight,
|
||||
addressString, viewKeyString, spendKeyString);
|
||||
Wallet wallet = new Wallet(walletHandle);
|
||||
manageWallet(wallet.getName(), wallet);
|
||||
@@ -134,6 +134,10 @@ public class WalletManager {
|
||||
return closed;
|
||||
}
|
||||
|
||||
public boolean walletExists(File aFile) {
|
||||
return walletExists(aFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
public native boolean walletExists(String path);
|
||||
|
||||
public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
|
||||
@@ -146,6 +150,31 @@ public class WalletManager {
|
||||
public String address;
|
||||
}
|
||||
|
||||
public WalletInfo getWalletInfo(File wallet) {
|
||||
WalletInfo info = new WalletInfo();
|
||||
info.path = wallet.getParentFile();
|
||||
info.name = wallet.getName();
|
||||
File addressFile = new File(info.path, info.name + ".address.txt");
|
||||
//Log.d(TAG, addressFile.getAbsolutePath());
|
||||
info.address = "??????";
|
||||
BufferedReader addressReader = null;
|
||||
try {
|
||||
addressReader = new BufferedReader(new FileReader(addressFile));
|
||||
info.address = addressReader.readLine();
|
||||
} catch (IOException ex) {
|
||||
Log.d(TAG, ex.getLocalizedMessage());
|
||||
} finally {
|
||||
if (addressReader != null) {
|
||||
try {
|
||||
addressReader.close();
|
||||
} catch (IOException ex) {
|
||||
// that's just too bad
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public List<WalletInfo> findWallets(File path) {
|
||||
List<WalletInfo> wallets = new ArrayList<>();
|
||||
Log.d(TAG, "Scanning: " + path.getAbsolutePath());
|
||||
@@ -155,29 +184,9 @@ public class WalletManager {
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < found.length; i++) {
|
||||
WalletInfo info = new WalletInfo();
|
||||
info.path = path;
|
||||
String filename = found[i].getName();
|
||||
info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1
|
||||
File addressFile = new File(path, info.name + ".address.txt");
|
||||
//Log.d(TAG, addressFile.getAbsolutePath());
|
||||
info.address = "??????";
|
||||
BufferedReader addressReader = null;
|
||||
try {
|
||||
addressReader = new BufferedReader(new FileReader(addressFile));
|
||||
info.address = addressReader.readLine();
|
||||
} catch (IOException ex) {
|
||||
Log.d(TAG, ex.getLocalizedMessage());
|
||||
} finally {
|
||||
if (addressReader != null) {
|
||||
try {
|
||||
addressReader.close();
|
||||
} catch (IOException ex) {
|
||||
// that's just too bad
|
||||
}
|
||||
}
|
||||
}
|
||||
wallets.add(info);
|
||||
File f = new File(found[i].getParent(), filename.substring(0, filename.length() - 5)); // 5 is length of ".keys"+1
|
||||
wallets.add(getWalletInfo(f));
|
||||
}
|
||||
return wallets;
|
||||
}
|
||||
|
@@ -19,10 +19,7 @@ package com.m2049r.xmrwallet.service;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -30,13 +27,11 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.WalletActivity;
|
||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||
import com.m2049r.xmrwallet.model.TransactionHistory;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletListener;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
@@ -44,6 +39,8 @@ import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.TxData;
|
||||
|
||||
public class WalletService extends Service {
|
||||
public static boolean Running = false;
|
||||
|
||||
final static String TAG = "WalletService";
|
||||
final static int NOTIFICATION_ID = 2049;
|
||||
|
||||
@@ -400,9 +397,6 @@ public class WalletService extends Service {
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
//mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
//showNotification();
|
||||
|
||||
// We are using a HandlerThread and a Looper to avoid loading and closing
|
||||
// concurrency
|
||||
MoneroHandlerThread thread = new MoneroHandlerThread("WalletService",
|
||||
@@ -419,8 +413,6 @@ public class WalletService extends Service {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.d(TAG, "onDestroy()");
|
||||
// Cancel the persistent notification.
|
||||
//mNM.cancel(NOTIFICATION);
|
||||
if (this.listener != null) {
|
||||
Log.w(TAG, "onDestroy() with active listener");
|
||||
// no need to stop() here because the wallet closing should have been triggered
|
||||
@@ -438,7 +430,8 @@ public class WalletService extends Service {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// when the activity satrts the service, it expects to start it for a new wallet
|
||||
Running = true;
|
||||
// when the activity starts the service, it expects to start it for a new wallet
|
||||
// the service is possibly still occupied with saving the last opened wallet
|
||||
// so we queue the open request
|
||||
// this should not matter since the old activity is not getting updates
|
||||
@@ -514,6 +507,7 @@ public class WalletService extends Service {
|
||||
}
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
Running = false;
|
||||
}
|
||||
|
||||
private Wallet loadWallet(String walletName, String walletPassword) {
|
||||
@@ -533,7 +527,7 @@ public class WalletService extends Service {
|
||||
}
|
||||
|
||||
private Wallet openWallet(String walletName, String walletPassword) {
|
||||
String path = Helper.getWalletPath(getApplicationContext(), walletName);
|
||||
String path = Helper.getWalletFile(getApplicationContext(), walletName).getAbsolutePath();
|
||||
showProgress(20);
|
||||
Wallet wallet = null;
|
||||
WalletManager walletMgr = WalletManager.getInstance();
|
||||
@@ -563,7 +557,7 @@ public class WalletService extends Service {
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
|
||||
Notification notification = new Notification.Builder(this)
|
||||
.setContentTitle(getString(R.string.service_description))
|
||||
.setSmallIcon(R.drawable.ic_notification_sync_32_32)
|
||||
.setSmallIcon(R.drawable.ic_monero_32dp)
|
||||
.setContentIntent(pendingIntent)
|
||||
.build();
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
|
@@ -19,10 +19,11 @@ package com.m2049r.xmrwallet.util;
|
||||
public class BarcodeData {
|
||||
public String address = null;
|
||||
public String paymentId = null;
|
||||
//String amount = null:
|
||||
public long amount = -1;
|
||||
|
||||
public BarcodeData(String address, String paymentId) {
|
||||
public BarcodeData(String address, String paymentId, long amount) {
|
||||
this.address = address;
|
||||
this.paymentId = paymentId;
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
@@ -21,12 +21,20 @@ import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
|
||||
import java.io.File;
|
||||
@@ -90,12 +98,16 @@ public class Helper {
|
||||
}
|
||||
}
|
||||
|
||||
static public String getWalletPath(Context context, String aWalletName) {
|
||||
// static public String getWalletPath(Context context, String aWalletName) {
|
||||
// return getWalletFile(context, aWalletName).getAbsolutePath();
|
||||
// }
|
||||
|
||||
static public File getWalletFile(Context context, String aWalletName) {
|
||||
File walletDir = getStorageRoot(context);
|
||||
//d(TAG, "walletdir=" + walletDir.getAbsolutePath());
|
||||
File f = new File(walletDir, aWalletName);
|
||||
Log.d(TAG, "wallet = " + f.getAbsolutePath() + " size=" + f.length());
|
||||
return f.getAbsolutePath();
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Checks if external storage is available for read and write */
|
||||
@@ -136,4 +148,41 @@ public class Helper {
|
||||
}
|
||||
}
|
||||
|
||||
static public String getDisplayAmount(long amount) {
|
||||
String s = Wallet.getDisplayAmount(amount);
|
||||
int lastZero = 0;
|
||||
int decimal = 0;
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
if ((lastZero == 0) && (s.charAt(i) != '0')) lastZero = i + 1;
|
||||
// TODO i18n
|
||||
if (s.charAt(i) == '.') {
|
||||
decimal = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Log.d(TAG, decimal + "/" + lastZero + "/" + s);
|
||||
int cutoff = Math.max(lastZero, decimal + 2);
|
||||
return s.substring(0, cutoff);
|
||||
}
|
||||
|
||||
public static Bitmap getBitmap(Context context, int drawableId) {
|
||||
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return BitmapFactory.decodeResource(context.getResources(), drawableId);
|
||||
} else if (drawable instanceof VectorDrawable) {
|
||||
return getBitmap((VectorDrawable) drawable);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported drawable type");
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
|
||||
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
vectorDrawable.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
14
app/src/main/res/drawable/ic_monero_32dp.xml
Normal file
14
app/src/main/res/drawable/ic_monero_32dp.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportHeight="75.0"
|
||||
android:viewportWidth="75.0">
|
||||
|
||||
<path
|
||||
android:fillColor="#ff6600"
|
||||
android:pathData="M 37.3,0.35329395 c -20.377,0 -36.903,16.524 -36.903,36.902 0,4.074 0.66,7.992 1.88,11.657 l 11.036,0 0,-31.049 23.987,23.987 23.987,-23.987 0,31.049 11.037,0 c 1.22,-3.665 1.88,-7.583 1.88,-11.657 0,-20.378 -16.526,-36.902 -36.904,-36.902" />
|
||||
<path
|
||||
android:fillColor="#4c4c4c"
|
||||
android:pathData="M 21.3164,36.895994 l 0,19.537 -15.55,0 c 6.478,10.628 18.178,17.726 31.533,17.726 13.355,0 25.056,-7.098 31.533,-17.726 l -15.549,0 0,-19.537 -15.984,15.984 z" />
|
||||
|
||||
</vector>
|
21
app/src/main/res/drawable/ic_monero_qr.xml
Normal file
21
app/src/main/res/drawable/ic_monero_qr.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="100dp"
|
||||
android:height="100dp"
|
||||
android:viewportHeight="75.0"
|
||||
android:viewportWidth="75.0">
|
||||
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData=" M 37.3, 37.3
|
||||
m -36.9, 0
|
||||
a 36.9,36.9 0 1,0 73.8,0
|
||||
a 36.9,36.9 0 1,0 -73.8,0" />
|
||||
|
||||
<path
|
||||
android:fillColor="#ff6600"
|
||||
android:pathData="M 37.3,0.35329395 c -20.377,0 -36.903,16.524 -36.903,36.902 0,4.074 0.66,7.992 1.88,11.657 l 11.036,0 0,-31.049 23.987,23.987 23.987,-23.987 0,31.049 11.037,0 c 1.22,-3.665 1.88,-7.583 1.88,-11.657 0,-20.378 -16.526,-36.902 -36.904,-36.902" />
|
||||
<path
|
||||
android:fillColor="#4c4c4c"
|
||||
android:pathData="M 21.3164,36.895994 l 0,19.537 -15.55,0 c 6.478,10.628 18.178,17.726 31.533,17.726 13.355,0 25.056,-7.098 31.533,-17.726 l -15.549,0 0,-19.537 -15.984,15.984 z" />
|
||||
|
||||
</vector>
|
33
app/src/main/res/drawable/ic_monero_qr_24dp.xml
Normal file
33
app/src/main/res/drawable/ic_monero_qr_24dp.xml
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.8 KiB |
@@ -4,19 +4,13 @@
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<ProgressBar
|
||||
android:id="@+id/pbProgress"
|
||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8sp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pbProgress"
|
||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="invisible" />
|
||||
</LinearLayout>
|
||||
android:visibility="invisible" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -143,7 +137,6 @@
|
||||
android:id="@+id/tvWalletSpendKey"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:selectAllOnFocus="true"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/colorPrimaryDark"
|
||||
android:textIsSelectable="true"
|
||||
|
@@ -4,14 +4,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp" >
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPasswordLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Wallet Password"
|
||||
android:labelFor="@+id/etPassword"
|
||||
android:text="@string/prompt_password"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<EditText
|
||||
@@ -19,7 +19,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="normal"
|
||||
android:inputType="textPassword" >
|
||||
android:inputType="textPassword">
|
||||
|
||||
|
||||
</EditText>
|
||||
|
24
app/src/main/res/layout/prompt_rename.xml
Normal file
24
app/src/main/res/layout/prompt_rename.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/layout_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvRenameLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/prompt_rename"
|
||||
android:labelFor="@+id/etRename"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etRename"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="normal"
|
||||
android:inputType="text" />
|
||||
|
||||
</LinearLayout>
|
122
app/src/main/res/layout/receive_fragment.xml
Normal file
122
app/src/main/res/layout/receive_fragment.xml
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pbProgress"
|
||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAddress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4sp"
|
||||
android:layout_marginTop="4sp"
|
||||
android:textIsSelectable="true"
|
||||
android:selectAllOnFocus="true"
|
||||
android:hint="@string/send_address_hint"
|
||||
android:textAlignment="center"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4sp"
|
||||
android:layout_marginTop="4sp"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="10">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="8sp"
|
||||
android:layout_weight="3"
|
||||
android:text="@string/receive_paymentid_label"
|
||||
android:textAlignment="textEnd"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etPaymentId"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="5"
|
||||
android:enabled="false"
|
||||
android:hint="@string/receive_paymentid_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="textStart"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bPaymentId"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="2"
|
||||
android:background="@color/colorPrimary"
|
||||
android:enabled="false"
|
||||
android:minHeight="36sp"
|
||||
android:text="@string/receive_paymentid_button"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4sp"
|
||||
android:layout_marginTop="4sp"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="10">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="8sp"
|
||||
android:layout_weight="3"
|
||||
android:text="@string/send_amount_label"
|
||||
android:textAlignment="textEnd"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etAmount"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="7"
|
||||
android:enabled="false"
|
||||
android:hint="@string/receive_amount_hint"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="numberDecimal"
|
||||
android:textAlignment="textStart"
|
||||
android:textSize="24sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/bGenerate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4sp"
|
||||
android:layout_marginTop="4sp"
|
||||
android:background="@color/colorPrimary"
|
||||
android:enabled="false"
|
||||
android:minHeight="36sp"
|
||||
android:text="@string/receive_generate_hint" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/qrCode"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_margin="16sp"
|
||||
android:adjustViewBounds="true" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etDummy"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="0sp" />
|
||||
|
||||
</LinearLayout>
|
@@ -52,7 +52,7 @@
|
||||
android:textSize="16sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bAddress"
|
||||
android:id="@+id/bScan"
|
||||
android:layout_width="0sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
@@ -3,6 +3,24 @@
|
||||
|
||||
<item
|
||||
android:id="@+id/action_info"
|
||||
android:icon="@drawable/ic_info_black_24dp"
|
||||
android:title="@string/menu_info" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_receive"
|
||||
android:icon="@drawable/ic_monero_qr_24dp"
|
||||
android:title="@string/menu_receive" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_rename"
|
||||
android:title="@string/menu_rename" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_backup"
|
||||
android:title="@string/menu_backup" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_archive"
|
||||
android:title="@string/menu_archive" />
|
||||
|
||||
</menu>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user