mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-16 10:10:50 +02:00
Compare commits
35 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 | ||
![]() |
5b38cc438c | ||
![]() |
1eac363102 | ||
![]() |
e51425bc2e | ||
![]() |
f5535dbefa |
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@@ -1,2 +1,2 @@
|
|||||||
workspace.xml
|
workspace.xml
|
||||||
markdown-navigator*
|
markdown-*
|
||||||
|
10
.idea/libraries/core_1_9_8.xml
generated
Normal file
10
.idea/libraries/core_1_9_8.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="core-1.9.8">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/jars/classes.jar!/" />
|
||||||
|
<root url="file://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/res" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
11
.idea/libraries/core_3_3_0.xml
generated
Normal file
11
.idea/libraries/core_3_3_0.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="core-3.3.0">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/73c49077166faa4c3c0059c5f583d1d7bd1475fe/core-3.3.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/39d966e052e28fc7d83793b02e0af97ccf955745/core-3.3.0-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
10
.idea/libraries/zxing_1_9_8.xml
generated
Normal file
10
.idea/libraries/zxing_1_9_8.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="zxing-1.9.8">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/jars/classes.jar!/" />
|
||||||
|
<root url="file://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/res" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
@@ -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/
|
- Monerujo means "Monero Wallet" according to https://www.reddit.com/r/Monero/comments/3exy7t/esperanto_corner/
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- wallet backup functions
|
|
||||||
- review visibility of methods/classes
|
- review visibility of methods/classes
|
||||||
- more sensible error dialogs
|
- more sensible error dialogs
|
||||||
- check licenses of included libraries; License Dialog
|
- check licenses of included libraries; License Dialog
|
||||||
|
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 7
|
versionCode 11
|
||||||
versionName "0.5"
|
versionName "0.6"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
@@ -46,5 +46,6 @@ dependencies {
|
|||||||
compile 'com.android.support:support-v4:25.3.1'
|
compile 'com.android.support:support-v4:25.3.1'
|
||||||
compile 'com.android.support:recyclerview-v7:25.3.1'
|
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||||
compile 'com.android.support:cardview-v7:25.3.1'
|
compile 'com.android.support:cardview-v7:25.3.1'
|
||||||
|
compile 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
@@ -7,10 +7,11 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@drawable/ic_monero_32dp"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
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);
|
//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
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
|
Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
|
||||||
jobject walletInstance) {
|
jobject walletInstance) {
|
||||||
|
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
@@ -69,12 +69,9 @@ public class GenerateFragment extends Fragment {
|
|||||||
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
||||||
|
|
||||||
etWalletMnemonic.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etWalletMnemonic.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
etWalletAddress.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etWalletAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletViewKey.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etWalletViewKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletSpendKey.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etWalletSpendKey.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
|
|
||||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
|
||||||
//etWalletMnemonic.setTextIsSelectable(testnet);
|
|
||||||
|
|
||||||
Helper.showKeyboard(getActivity());
|
Helper.showKeyboard(getActivity());
|
||||||
etWalletName.addTextChangedListener(new TextWatcher() {
|
etWalletName.addTextChangedListener(new TextWatcher() {
|
||||||
@@ -298,8 +295,12 @@ public class GenerateFragment extends Fragment {
|
|||||||
private void generateWallet() {
|
private void generateWallet() {
|
||||||
String name = etWalletName.getText().toString();
|
String name = etWalletName.getText().toString();
|
||||||
if (name.length() == 0) return;
|
if (name.length() == 0) return;
|
||||||
String walletPath = Helper.getWalletPath(getActivity(), name);
|
if (name.charAt(0)=='.') {
|
||||||
if (WalletManager.getInstance().walletExists(walletPath)) {
|
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();
|
Toast.makeText(getActivity(), getString(R.string.generate_wallet_exists), Toast.LENGTH_LONG).show();
|
||||||
etWalletName.requestFocus();
|
etWalletName.requestFocus();
|
||||||
return;
|
return;
|
||||||
@@ -348,7 +349,7 @@ public class GenerateFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
Log.d(TAG, "onPause()");
|
Log.d(TAG, "onResume()");
|
||||||
activityCallback.setTitle(getString(R.string.generate_title));
|
activityCallback.setTitle(getString(R.string.generate_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -28,15 +30,13 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class GenerateReviewFragment extends Fragment {
|
public class GenerateReviewFragment extends Fragment {
|
||||||
static final String TAG = "GenerateReviewFragment";
|
static final String TAG = "GenerateReviewFragment";
|
||||||
static final public String VIEW_DETAILS = "details";
|
static final public String VIEW_TYPE_DETAILS = "details";
|
||||||
static final public String VIEW_ACCEPT = "accept";
|
static final public String VIEW_TYPE_ACCEPT = "accept";
|
||||||
static final public String VIEW_WALLET = "wallet";
|
static final public String VIEW_TYPE_WALLET = "wallet";
|
||||||
|
|
||||||
ProgressBar pbProgress;
|
ProgressBar pbProgress;
|
||||||
TextView tvWalletName;
|
TextView tvWalletName;
|
||||||
@@ -76,16 +76,12 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
showProgress();
|
showProgress();
|
||||||
|
|
||||||
Bundle b = getArguments();
|
Bundle args = getArguments();
|
||||||
String type = b.getString("type");
|
String path = args.getString("path");
|
||||||
if (!type.equals(VIEW_WALLET)) {
|
String password = args.getString("password");
|
||||||
String name = b.getString("name");
|
String type = args.getString("type");
|
||||||
String password = b.getString("password");
|
new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
|
||||||
tvWalletName.setText(new File(name).getName());
|
path, password, type);
|
||||||
show(name, password, type);
|
|
||||||
} else {
|
|
||||||
show(walletCallback.getWallet(), null, type);
|
|
||||||
}
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,41 +92,65 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
acceptCallback.onAccept(name, password);
|
acceptCallback.onAccept(name, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void show(final String walletPath, final String password, final String type) {
|
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||||
new Thread(null,
|
String type;
|
||||||
new Runnable() {
|
String password;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
String address;
|
||||||
|
String seed;
|
||||||
|
String viewKey;
|
||||||
|
boolean isWatchOnly;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
protected Boolean doInBackground(String... params) {
|
||||||
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
|
if (params.length != 3) return false;
|
||||||
getActivity().runOnUiThread(new Runnable() {
|
String walletPath = params[0];
|
||||||
public void run() {
|
password = params[1];
|
||||||
show(wallet, password, type);
|
type = params[2];
|
||||||
wallet.close();
|
|
||||||
|
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();
|
||||||
, "DetailsReview", MoneroHandlerThread.THREAD_STACK_SIZE).start();
|
seed = wallet.getSeed();
|
||||||
|
viewKey = wallet.getSecretViewKey();
|
||||||
|
isWatchOnly = wallet.isWatchOnly();
|
||||||
|
if (closeWallet) wallet.close();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void show(final Wallet wallet, final String password, final String type) {
|
@Override
|
||||||
if (type.equals(GenerateReviewFragment.VIEW_ACCEPT)) {
|
protected void onPostExecute(Boolean result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
if (result) {
|
||||||
|
if (type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT)) {
|
||||||
tvWalletPassword.setText(password);
|
tvWalletPassword.setText(password);
|
||||||
bAccept.setVisibility(View.VISIBLE);
|
bAccept.setVisibility(View.VISIBLE);
|
||||||
bAccept.setEnabled(true);
|
bAccept.setEnabled(true);
|
||||||
}
|
}
|
||||||
tvWalletName.setText(wallet.getName());
|
tvWalletName.setText(name);
|
||||||
tvWalletAddress.setText(wallet.getAddress());
|
tvWalletAddress.setText(address);
|
||||||
tvWalletMnemonic.setText(wallet.getSeed());
|
tvWalletMnemonic.setText(seed);
|
||||||
tvWalletViewKey.setText(wallet.getSecretViewKey());
|
tvWalletViewKey.setText(viewKey);
|
||||||
String spend = wallet.isWatchOnly() ? "" : "not available - use seed for recovery";
|
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
|
if (spend.length() > 0) { //TODO should be == 64, but spendkey is not in the API yet
|
||||||
tvWalletSpendKey.setText(spend);
|
tvWalletSpendKey.setText(spend);
|
||||||
} else {
|
} else {
|
||||||
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
|
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
hideProgress();
|
hideProgress();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GenerateReviewFragment.Listener acceptCallback = null;
|
GenerateReviewFragment.Listener acceptCallback = null;
|
||||||
GenerateReviewFragment.ListenerWithWallet walletCallback = null;
|
GenerateReviewFragment.ListenerWithWallet walletCallback = null;
|
||||||
@@ -141,6 +161,7 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
|
|
||||||
public interface ListenerWithWallet {
|
public interface ListenerWithWallet {
|
||||||
Wallet getWallet();
|
Wallet getWallet();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -82,9 +83,17 @@ public class LoginFragment extends Fragment {
|
|||||||
|
|
||||||
File getStorageRoot();
|
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();
|
void onAddWallet();
|
||||||
|
|
||||||
@@ -117,14 +126,14 @@ public class LoginFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
Log.d(TAG, "onPause()");
|
Log.d(TAG, "onResume()");
|
||||||
activityCallback.setTitle(getString(R.string.login_activity_name));
|
activityCallback.setTitle(getString(R.string.login_activity_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
Log.d(TAG, "onCreateView");
|
||||||
View view = inflater.inflate(R.layout.login_fragment, container, false);
|
View view = inflater.inflate(R.layout.login_fragment, container, false);
|
||||||
|
|
||||||
tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet);
|
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();
|
loadList();
|
||||||
return view;
|
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();
|
WalletManager mgr = WalletManager.getInstance();
|
||||||
List<WalletManager.WalletInfo> walletInfos =
|
List<WalletManager.WalletInfo> walletInfos =
|
||||||
mgr.findWallets(activityCallback.getStorageRoot());
|
mgr.findWallets(activityCallback.getStorageRoot());
|
||||||
@@ -408,32 +393,52 @@ public class LoginFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem item) {
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
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()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_info:
|
case R.id.action_info:
|
||||||
String listItem = (String) listView.getItemAtPosition(info.position);
|
showInfo(name);
|
||||||
return showInfo(listItem);
|
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:
|
default:
|
||||||
return super.onContextItemSelected(item);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showInfo(@NonNull String name) {
|
||||||
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
||||||
|
|
||||||
activityCallback.onWalletDetails(wallet);
|
activityCallback.onWalletDetails(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean showReceive(@NonNull String name) {
|
||||||
|
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
|
||||||
|
|
||||||
|
activityCallback.onWalletReceive(name);
|
||||||
return true;
|
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
112
app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java
Normal file
112
app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 dm77, 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
import com.m2049r.xmrwallet.util.BarcodeData;
|
||||||
|
|
||||||
|
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||||
|
|
||||||
|
public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler {
|
||||||
|
static final String TAG = "ScannerFragment";
|
||||||
|
|
||||||
|
Listener activityCallback;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
boolean onAddressScanned(String uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZXingScannerView mScannerView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
Log.d(TAG, "onCreateView");
|
||||||
|
mScannerView = new ZXingScannerView(getActivity());
|
||||||
|
return mScannerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Log.d(TAG, "onResume");
|
||||||
|
mScannerView.setResultHandler(this);
|
||||||
|
mScannerView.startCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) &&
|
||||||
|
(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();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_qr_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note from dm77:
|
||||||
|
// * Wait 2 seconds to resume the preview.
|
||||||
|
// * On older devices continuously stopping and resuming camera preview can result in freezing the app.
|
||||||
|
// * I don't know why this is the case but I don't have the time to figure out.
|
||||||
|
Handler handler = new Handler();
|
||||||
|
handler.postDelayed(new
|
||||||
|
|
||||||
|
Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mScannerView.resumeCameraPreview(ScannerFragment.this);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
Log.d(TAG, "onPause");
|
||||||
|
mScannerView.stopCamera();
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
//Log.d(TAG, "attaching scan");
|
||||||
|
if (context instanceof Listener) {
|
||||||
|
this.activityCallback = (Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -40,14 +42,16 @@ import com.m2049r.xmrwallet.model.PendingTransaction;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
import com.m2049r.xmrwallet.util.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.util.TxData;
|
import com.m2049r.xmrwallet.util.TxData;
|
||||||
|
|
||||||
public class SendFragment extends Fragment {
|
public class SendFragment extends Fragment {
|
||||||
static final String TAG = "GenerateFragment";
|
static final String TAG = "SendFragment";
|
||||||
|
|
||||||
EditText etAddress;
|
EditText etAddress;
|
||||||
EditText etPaymentId;
|
EditText etPaymentId;
|
||||||
EditText etAmount;
|
EditText etAmount;
|
||||||
|
Button bScan;
|
||||||
Button bSweep;
|
Button bSweep;
|
||||||
Spinner sMixin;
|
Spinner sMixin;
|
||||||
Spinner sPriority;
|
Spinner sPriority;
|
||||||
@@ -80,6 +84,7 @@ public class SendFragment extends Fragment {
|
|||||||
etAddress = (EditText) view.findViewById(R.id.etAddress);
|
etAddress = (EditText) view.findViewById(R.id.etAddress);
|
||||||
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
|
etPaymentId = (EditText) view.findViewById(R.id.etPaymentId);
|
||||||
etAmount = (EditText) view.findViewById(R.id.etAmount);
|
etAmount = (EditText) view.findViewById(R.id.etAmount);
|
||||||
|
bScan = (Button) view.findViewById(R.id.bScan);
|
||||||
bSweep = (Button) view.findViewById(R.id.bSweep);
|
bSweep = (Button) view.findViewById(R.id.bSweep);
|
||||||
bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend);
|
bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend);
|
||||||
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
|
bPaymentId = (Button) view.findViewById(R.id.bPaymentId);
|
||||||
@@ -95,8 +100,8 @@ public class SendFragment extends Fragment {
|
|||||||
|
|
||||||
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
pbProgress = (ProgressBar) view.findViewById(R.id.pbProgress);
|
||||||
|
|
||||||
etAddress.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etAddress.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etPaymentId.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
etNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
|
||||||
Helper.showKeyboard(getActivity());
|
Helper.showKeyboard(getActivity());
|
||||||
@@ -194,10 +199,18 @@ public class SendFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bScan.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
activityCallback.onScanAddress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
bPaymentId.setOnClickListener(new View.OnClickListener() {
|
bPaymentId.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
etPaymentId.setText((activityCallback.generatePaymentId()));
|
etPaymentId.setText((Wallet.generatePaymentId()));
|
||||||
|
etPaymentId.setSelection(etPaymentId.getText().length());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -231,8 +244,15 @@ public class SendFragment extends Fragment {
|
|||||||
if (testnet) {
|
if (testnet) {
|
||||||
send();
|
send();
|
||||||
} else {
|
} else {
|
||||||
|
etNotes.setEnabled(false);
|
||||||
|
Handler handler = new Handler();
|
||||||
|
handler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
bReallySend.setVisibility(View.VISIBLE);
|
bReallySend.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -256,11 +276,7 @@ public class SendFragment extends Fragment {
|
|||||||
|
|
||||||
private boolean addressOk() {
|
private boolean addressOk() {
|
||||||
String address = etAddress.getText().toString();
|
String address = etAddress.getText().toString();
|
||||||
if (WalletManager.getInstance().isTestNet()) {
|
return Helper.isAddressOk(address, WalletManager.getInstance().isTestNet());
|
||||||
return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0));
|
|
||||||
} else {
|
|
||||||
return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean amountOk() {
|
private boolean amountOk() {
|
||||||
@@ -270,7 +286,7 @@ public class SendFragment extends Fragment {
|
|||||||
|
|
||||||
private boolean paymentIdOk() {
|
private boolean paymentIdOk() {
|
||||||
String paymentId = etPaymentId.getText().toString();
|
String paymentId = etPaymentId.getText().toString();
|
||||||
return paymentId.isEmpty() || activityCallback.isPaymentIdValid(paymentId);
|
return paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareSend() {
|
private void prepareSend() {
|
||||||
@@ -306,6 +322,7 @@ public class SendFragment extends Fragment {
|
|||||||
etAddress.setEnabled(false);
|
etAddress.setEnabled(false);
|
||||||
etPaymentId.setEnabled(false);
|
etPaymentId.setEnabled(false);
|
||||||
etAmount.setEnabled(false);
|
etAmount.setEnabled(false);
|
||||||
|
bScan.setEnabled(false);
|
||||||
bPaymentId.setEnabled(false);
|
bPaymentId.setEnabled(false);
|
||||||
bSweep.setEnabled(false);
|
bSweep.setEnabled(false);
|
||||||
bPrepareSend.setEnabled(false);
|
bPrepareSend.setEnabled(false);
|
||||||
@@ -317,10 +334,13 @@ public class SendFragment extends Fragment {
|
|||||||
etAddress.setEnabled(true);
|
etAddress.setEnabled(true);
|
||||||
etPaymentId.setEnabled(true);
|
etPaymentId.setEnabled(true);
|
||||||
etAmount.setEnabled(true);
|
etAmount.setEnabled(true);
|
||||||
|
bScan.setEnabled(true);
|
||||||
bPaymentId.setEnabled(true);
|
bPaymentId.setEnabled(true);
|
||||||
bSweep.setEnabled(true);
|
bSweep.setEnabled(true);
|
||||||
bPrepareSend.setEnabled(true);
|
bPrepareSend.setEnabled(true);
|
||||||
llConfirmSend.setVisibility(View.GONE);
|
llConfirmSend.setVisibility(View.GONE);
|
||||||
|
bSend.setEnabled(true);
|
||||||
|
etNotes.setEnabled(true);
|
||||||
bReallySend.setVisibility(View.GONE);
|
bReallySend.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,14 +359,53 @@ public class SendFragment extends Fragment {
|
|||||||
|
|
||||||
void onSend(String notes);
|
void onSend(String notes);
|
||||||
|
|
||||||
String generatePaymentId();
|
|
||||||
|
|
||||||
boolean isPaymentIdValid(String paymentId);
|
|
||||||
|
|
||||||
String getWalletAddress();
|
String getWalletAddress();
|
||||||
|
|
||||||
void onDisposeRequest();
|
void onDisposeRequest();
|
||||||
|
|
||||||
|
void onScanAddress();
|
||||||
|
|
||||||
|
BarcodeData getScannedData();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -16,28 +16,23 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Transfer;
|
import com.m2049r.xmrwallet.model.Transfer;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
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.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,21 +16,20 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.ClipData;
|
|
||||||
import android.content.ClipboardManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.constraint.ConstraintLayout;
|
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.DividerItemDecoration;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.Interpolator;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
@@ -38,9 +37,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Transfer;
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -59,6 +57,19 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
ProgressBar pbProgress;
|
ProgressBar pbProgress;
|
||||||
Button bSend;
|
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
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
@@ -69,9 +80,9 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
clProgress = (ConstraintLayout) view.findViewById(R.id.clProgress);
|
clProgress = (ConstraintLayout) view.findViewById(R.id.clProgress);
|
||||||
llUnconfirmedAmount = (LinearLayout) view.findViewById(R.id.llUnconfirmedAmount);
|
llUnconfirmedAmount = (LinearLayout) view.findViewById(R.id.llUnconfirmedAmount);
|
||||||
tvBalance = (TextView) view.findViewById(R.id.tvBalance);
|
tvBalance = (TextView) view.findViewById(R.id.tvBalance);
|
||||||
tvBalance.setText(getDisplayAmount(0));
|
tvBalance.setText(Helper.getDisplayAmount(0));
|
||||||
tvUnconfirmedAmount = (TextView) view.findViewById(R.id.tvUnconfirmedAmount);
|
tvUnconfirmedAmount = (TextView) view.findViewById(R.id.tvUnconfirmedAmount);
|
||||||
tvUnconfirmedAmount.setText(getDisplayAmount(0));
|
tvUnconfirmedAmount.setText(Helper.getDisplayAmount(0));
|
||||||
tvBlockHeightProgress = (TextView) view.findViewById(R.id.tvBlockHeightProgress);
|
tvBlockHeightProgress = (TextView) view.findViewById(R.id.tvBlockHeightProgress);
|
||||||
|
|
||||||
bSend = (Button) view.findViewById(R.id.bSend);
|
bSend = (Button) view.findViewById(R.id.bSend);
|
||||||
@@ -175,23 +186,6 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
private long firstBlock = 0;
|
private long firstBlock = 0;
|
||||||
private String walletTitle = null;
|
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) {
|
private void updateStatus(Wallet wallet) {
|
||||||
Log.d(TAG, "updateStatus()");
|
Log.d(TAG, "updateStatus()");
|
||||||
if (walletTitle == null) {
|
if (walletTitle == null) {
|
||||||
@@ -200,8 +194,8 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
}
|
}
|
||||||
long balance = wallet.getBalance();
|
long balance = wallet.getBalance();
|
||||||
long unlockedBalance = wallet.getUnlockedBalance();
|
long unlockedBalance = wallet.getUnlockedBalance();
|
||||||
tvBalance.setText(getDisplayAmount(unlockedBalance));
|
tvBalance.setText(Helper.getDisplayAmount(unlockedBalance));
|
||||||
tvUnconfirmedAmount.setText(getDisplayAmount(balance - unlockedBalance));
|
tvUnconfirmedAmount.setText(Helper.getDisplayAmount(balance - unlockedBalance));
|
||||||
// balance cannot be less than unlockedBalance
|
// balance cannot be less than unlockedBalance
|
||||||
/*if (balance != unlockedBalance) {
|
/*if (balance != unlockedBalance) {
|
||||||
llPendingAmount.setVisibility(View.VISIBLE);
|
llPendingAmount.setVisibility(View.VISIBLE);
|
||||||
@@ -259,6 +253,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
boolean isWatchOnly();
|
boolean isWatchOnly();
|
||||||
|
|
||||||
String getTxKey(String txId);
|
String getTxKey(String txId);
|
||||||
|
|
||||||
|
void onWalletReceive();
|
||||||
|
|
||||||
|
boolean hasWallet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -238,6 +238,7 @@ public class Wallet {
|
|||||||
public native void setDefaultMixin(int mixin);
|
public native void setDefaultMixin(int mixin);
|
||||||
|
|
||||||
public native boolean setUserNote(String txid, String note);
|
public native boolean setUserNote(String txid, String note);
|
||||||
|
|
||||||
public native String getUserNote(String txid);
|
public native String getUserNote(String txid);
|
||||||
|
|
||||||
public native String getTxKey(String txid);
|
public native String getTxKey(String txid);
|
||||||
|
@@ -71,8 +71,8 @@ public class WalletManager {
|
|||||||
managedWallets.remove(walletId);
|
managedWallets.remove(walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet createWallet(String path, String password, String language) {
|
public Wallet createWallet(File aFile, String password, String language) {
|
||||||
long walletHandle = createWalletJ(path, password, language, isTestNet());
|
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, isTestNet());
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet.getName(), wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
@@ -89,14 +89,14 @@ public class WalletManager {
|
|||||||
|
|
||||||
private native long openWalletJ(String path, String password, boolean isTestNet);
|
private native long openWalletJ(String path, String password, boolean isTestNet);
|
||||||
|
|
||||||
public Wallet recoveryWallet(String path, String mnemonic) {
|
public Wallet recoveryWallet(File aFile, String mnemonic) {
|
||||||
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
Wallet wallet = recoveryWallet(aFile, mnemonic, 0);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet.getName(), wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet recoveryWallet(String path, String mnemonic, long restoreHeight) {
|
public Wallet recoveryWallet(File aFile, String mnemonic, long restoreHeight) {
|
||||||
long walletHandle = recoveryWalletJ(path, mnemonic, isTestNet(), restoreHeight);
|
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), mnemonic, isTestNet(), restoreHeight);
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet.getName(), wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
@@ -104,9 +104,9 @@ public class WalletManager {
|
|||||||
|
|
||||||
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
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) {
|
String addressString, String viewKeyString, String spendKeyString) {
|
||||||
long walletHandle = createWalletFromKeysJ(path, language, isTestNet(), restoreHeight,
|
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), language, isTestNet(), restoreHeight,
|
||||||
addressString, viewKeyString, spendKeyString);
|
addressString, viewKeyString, spendKeyString);
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet.getName(), wallet);
|
||||||
@@ -134,6 +134,10 @@ public class WalletManager {
|
|||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean walletExists(File aFile) {
|
||||||
|
return walletExists(aFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
public native boolean walletExists(String path);
|
public native boolean walletExists(String path);
|
||||||
|
|
||||||
public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
|
public native boolean verifyWalletPassword(String keys_file_name, String password, boolean watch_only);
|
||||||
@@ -146,20 +150,11 @@ public class WalletManager {
|
|||||||
public String address;
|
public String address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WalletInfo> findWallets(File path) {
|
public WalletInfo getWalletInfo(File wallet) {
|
||||||
List<WalletInfo> wallets = new ArrayList<>();
|
|
||||||
Log.d(TAG, "Scanning: " + path.getAbsolutePath());
|
|
||||||
File[] found = path.listFiles(new FilenameFilter() {
|
|
||||||
public boolean accept(File dir, String filename) {
|
|
||||||
return filename.endsWith(".keys");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (int i = 0; i < found.length; i++) {
|
|
||||||
WalletInfo info = new WalletInfo();
|
WalletInfo info = new WalletInfo();
|
||||||
info.path = path;
|
info.path = wallet.getParentFile();
|
||||||
String filename = found[i].getName();
|
info.name = wallet.getName();
|
||||||
info.name = filename.substring(0, filename.length() - 5); // 5 is length of ".keys"+1
|
File addressFile = new File(info.path, info.name + ".address.txt");
|
||||||
File addressFile = new File(path, info.name + ".address.txt");
|
|
||||||
//Log.d(TAG, addressFile.getAbsolutePath());
|
//Log.d(TAG, addressFile.getAbsolutePath());
|
||||||
info.address = "??????";
|
info.address = "??????";
|
||||||
BufferedReader addressReader = null;
|
BufferedReader addressReader = null;
|
||||||
@@ -177,7 +172,21 @@ public class WalletManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wallets.add(info);
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WalletInfo> findWallets(File path) {
|
||||||
|
List<WalletInfo> wallets = new ArrayList<>();
|
||||||
|
Log.d(TAG, "Scanning: " + path.getAbsolutePath());
|
||||||
|
File[] found = path.listFiles(new FilenameFilter() {
|
||||||
|
public boolean accept(File dir, String filename) {
|
||||||
|
return filename.endsWith(".keys");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (int i = 0; i < found.length; i++) {
|
||||||
|
String filename = found[i].getName();
|
||||||
|
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;
|
return wallets;
|
||||||
}
|
}
|
||||||
|
@@ -19,10 +19,7 @@ package com.m2049r.xmrwallet.service;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -30,13 +27,11 @@ import android.os.IBinder;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.WalletActivity;
|
import com.m2049r.xmrwallet.WalletActivity;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.model.TransactionHistory;
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletListener;
|
import com.m2049r.xmrwallet.model.WalletListener;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
@@ -44,6 +39,8 @@ import com.m2049r.xmrwallet.util.Helper;
|
|||||||
import com.m2049r.xmrwallet.util.TxData;
|
import com.m2049r.xmrwallet.util.TxData;
|
||||||
|
|
||||||
public class WalletService extends Service {
|
public class WalletService extends Service {
|
||||||
|
public static boolean Running = false;
|
||||||
|
|
||||||
final static String TAG = "WalletService";
|
final static String TAG = "WalletService";
|
||||||
final static int NOTIFICATION_ID = 2049;
|
final static int NOTIFICATION_ID = 2049;
|
||||||
|
|
||||||
@@ -127,6 +124,7 @@ public class WalletService extends Service {
|
|||||||
boolean fullRefresh = false;
|
boolean fullRefresh = false;
|
||||||
updateDaemonState(wallet, wallet.isSynchronized() ? height : 0);
|
updateDaemonState(wallet, wallet.isSynchronized() ? height : 0);
|
||||||
if (!wallet.isSynchronized()) {
|
if (!wallet.isSynchronized()) {
|
||||||
|
updated = true;
|
||||||
// we want to see our transactions as they come in
|
// we want to see our transactions as they come in
|
||||||
wallet.getHistory().refresh();
|
wallet.getHistory().refresh();
|
||||||
int txCount = wallet.getHistory().getCount();
|
int txCount = wallet.getHistory().getCount();
|
||||||
@@ -399,9 +397,6 @@ public class WalletService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
//mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
|
||||||
//showNotification();
|
|
||||||
|
|
||||||
// We are using a HandlerThread and a Looper to avoid loading and closing
|
// We are using a HandlerThread and a Looper to avoid loading and closing
|
||||||
// concurrency
|
// concurrency
|
||||||
MoneroHandlerThread thread = new MoneroHandlerThread("WalletService",
|
MoneroHandlerThread thread = new MoneroHandlerThread("WalletService",
|
||||||
@@ -418,8 +413,6 @@ public class WalletService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
Log.d(TAG, "onDestroy()");
|
Log.d(TAG, "onDestroy()");
|
||||||
// Cancel the persistent notification.
|
|
||||||
//mNM.cancel(NOTIFICATION);
|
|
||||||
if (this.listener != null) {
|
if (this.listener != null) {
|
||||||
Log.w(TAG, "onDestroy() with active listener");
|
Log.w(TAG, "onDestroy() with active listener");
|
||||||
// no need to stop() here because the wallet closing should have been triggered
|
// no need to stop() here because the wallet closing should have been triggered
|
||||||
@@ -437,7 +430,8 @@ public class WalletService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
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
|
// the service is possibly still occupied with saving the last opened wallet
|
||||||
// so we queue the open request
|
// so we queue the open request
|
||||||
// this should not matter since the old activity is not getting updates
|
// this should not matter since the old activity is not getting updates
|
||||||
@@ -513,6 +507,7 @@ public class WalletService extends Service {
|
|||||||
}
|
}
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
stopSelf();
|
stopSelf();
|
||||||
|
Running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Wallet loadWallet(String walletName, String walletPassword) {
|
private Wallet loadWallet(String walletName, String walletPassword) {
|
||||||
@@ -532,7 +527,7 @@ public class WalletService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Wallet openWallet(String walletName, String walletPassword) {
|
private Wallet openWallet(String walletName, String walletPassword) {
|
||||||
String path = Helper.getWalletPath(getApplicationContext(), walletName);
|
String path = Helper.getWalletFile(getApplicationContext(), walletName).getAbsolutePath();
|
||||||
showProgress(20);
|
showProgress(20);
|
||||||
Wallet wallet = null;
|
Wallet wallet = null;
|
||||||
WalletManager walletMgr = WalletManager.getInstance();
|
WalletManager walletMgr = WalletManager.getInstance();
|
||||||
@@ -562,7 +557,7 @@ public class WalletService extends Service {
|
|||||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
|
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
|
||||||
Notification notification = new Notification.Builder(this)
|
Notification notification = new Notification.Builder(this)
|
||||||
.setContentTitle(getString(R.string.service_description))
|
.setContentTitle(getString(R.string.service_description))
|
||||||
.setSmallIcon(R.drawable.ic_notification_sync_32_32)
|
.setSmallIcon(R.drawable.ic_monero_32dp)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.build();
|
.build();
|
||||||
startForeground(NOTIFICATION_ID, notification);
|
startForeground(NOTIFICATION_ID, notification);
|
||||||
|
29
app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java
Normal file
29
app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public class BarcodeData {
|
||||||
|
public String address = null;
|
||||||
|
public String paymentId = null;
|
||||||
|
public long amount = -1;
|
||||||
|
|
||||||
|
public BarcodeData(String address, String paymentId, long amount) {
|
||||||
|
this.address = address;
|
||||||
|
this.paymentId = paymentId;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
}
|
@@ -21,12 +21,21 @@ import android.app.Activity;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
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.os.Environment;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@@ -71,12 +80,34 @@ public class Helper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static public String getWalletPath(Context context, String aWalletName) {
|
public static final int PERMISSIONS_REQUEST_CAMERA = 1;
|
||||||
|
|
||||||
|
static public boolean getCameraPermission(Activity context) {
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||||
|
if (context.checkSelfPermission(Manifest.permission.CAMERA)
|
||||||
|
== PackageManager.PERMISSION_DENIED) {
|
||||||
|
Log.d(TAG, "Permission denied for CAMERA - requesting it");
|
||||||
|
String[] permissions = {Manifest.permission.CAMERA};
|
||||||
|
context.requestPermissions(permissions, PERMISSIONS_REQUEST_CAMERA);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
File walletDir = getStorageRoot(context);
|
||||||
//d(TAG, "walletdir=" + walletDir.getAbsolutePath());
|
//d(TAG, "walletdir=" + walletDir.getAbsolutePath());
|
||||||
File f = new File(walletDir, aWalletName);
|
File f = new File(walletDir, aWalletName);
|
||||||
Log.d(TAG, "wallet = " + f.getAbsolutePath() + " size=" + f.length());
|
Log.d(TAG, "wallet = " + f.getAbsolutePath() + " size=" + f.length());
|
||||||
return f.getAbsolutePath();
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if external storage is available for read and write */
|
/* Checks if external storage is available for read and write */
|
||||||
@@ -107,4 +138,51 @@ public class Helper {
|
|||||||
static public void hideKeyboardAlways(Activity act) {
|
static public void hideKeyboardAlways(Activity act) {
|
||||||
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public boolean isAddressOk(String address, boolean testnet) {
|
||||||
|
if (address == null) return false;
|
||||||
|
if (testnet) {
|
||||||
|
return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0));
|
||||||
|
} else {
|
||||||
|
return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="8sp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/pbProgress"
|
android:id="@+id/pbProgress"
|
||||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8sp"
|
||||||
android:visibility="invisible" />
|
android:visibility="invisible" />
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -143,7 +137,6 @@
|
|||||||
android:id="@+id/tvWalletSpendKey"
|
android:id="@+id/tvWalletSpendKey"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:selectAllOnFocus="true"
|
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/colorPrimaryDark"
|
android:textColor="@color/colorPrimaryDark"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
|
@@ -10,8 +10,8 @@
|
|||||||
android:id="@+id/tvPasswordLabel"
|
android:id="@+id/tvPasswordLabel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Wallet Password"
|
|
||||||
android:labelFor="@+id/etPassword"
|
android:labelFor="@+id/etPassword"
|
||||||
|
android:text="@string/prompt_password"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
|
||||||
<EditText
|
<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>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user