From bd598dedddca18b9769df1d014577ebcd261ac11 Mon Sep 17 00:00:00 2001
From: m2049r <30435443+m2049r@users.noreply.github.com>
Date: Wed, 16 Aug 2017 19:39:53 +0200
Subject: [PATCH] separate wallet generation & confirmation all methods of
recovery & creation implemented
---
.idea/misc.xml | 2 +-
.../m2049r/xmrwallet/GenerateFragment.java | 292 ++++++++++++++----
.../xmrwallet/GenerateReviewFragment.java | 116 +++++++
.../com/m2049r/xmrwallet/LoginActivity.java | 121 ++++++--
.../com/m2049r/xmrwallet/LoginFragment.java | 4 +-
.../com/m2049r/xmrwallet/WalletFragment.java | 6 +-
.../m2049r/xmrwallet/model/WalletManager.java | 17 +-
.../xmrwallet/service/WalletService.java | 1 +
app/src/main/res/layout/gen_fragment.xml | 171 +++++-----
.../main/res/layout/gen_review_fragment.xml | 162 ++++++++++
app/src/main/res/layout/login_fragment.xml | 6 +-
app/src/main/res/values/strings.xml | 31 +-
12 files changed, 747 insertions(+), 182 deletions(-)
create mode 100644 app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java
create mode 100644 app/src/main/res/layout/gen_review_fragment.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
index fbb6828..5d19981 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -37,7 +37,7 @@
-
+
diff --git a/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java b/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
index 9fc842d..56dfae2 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
import android.app.Fragment;
@@ -5,6 +21,7 @@ import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -24,15 +41,17 @@ import java.io.File;
// TODO: somehow show which net we are generating for
public class GenerateFragment extends Fragment {
+ static final String TAG = "GenerateFragment";
EditText etWalletName;
EditText etWalletPassword;
+ EditText etWalletAddress;
+ EditText etWalletMnemonic;
+ LinearLayout llRestoreKeys;
+ EditText etWalletViewKey;
+ EditText etWalletSpendKey;
+ EditText etWalletRestoreHeight;
Button bGenerate;
- LinearLayout llAccept;
- TextView tvWalletAddress;
- TextView tvWalletMnemonic;
- Button bAccept;
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -42,22 +61,27 @@ public class GenerateFragment extends Fragment {
etWalletName = (EditText) view.findViewById(R.id.etWalletName);
etWalletPassword = (EditText) view.findViewById(R.id.etWalletPassword);
+ etWalletMnemonic = (EditText) view.findViewById(R.id.etWalletMnemonic);
+ etWalletAddress = (EditText) view.findViewById(R.id.etWalletAddress);
+ llRestoreKeys = (LinearLayout) view.findViewById(R.id.llRestoreKeys);
+ etWalletViewKey = (EditText) view.findViewById(R.id.etWalletViewKey);
+ etWalletSpendKey = (EditText) view.findViewById(R.id.etWalletSpendKey);
+ etWalletRestoreHeight = (EditText) view.findViewById(R.id.etWalletRestoreHeight);
bGenerate = (Button) view.findViewById(R.id.bGenerate);
- llAccept = (LinearLayout) view.findViewById(R.id.llAccept);
- tvWalletAddress = (TextView) view.findViewById(R.id.tvWalletAddress);
- tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
- bAccept = (Button) view.findViewById(R.id.bAccept);
boolean testnet = WalletManager.getInstance().isTestNet();
- tvWalletMnemonic.setTextIsSelectable(testnet);
+ etWalletMnemonic.setTextIsSelectable(testnet);
etWalletName.requestFocus();
Helper.showKeyboard(getActivity());
- setGenerateEnabled();
etWalletName.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
- showMnemonic("");
+ if (etWalletName.length() > 0) {
+ bGenerate.setEnabled(true);
+ } else {
+ bGenerate.setEnabled(false);
+ }
}
@Override
@@ -76,11 +100,11 @@ public class GenerateFragment extends Fragment {
});
etWalletName.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (etWalletName.length() > 0) {
etWalletPassword.requestFocus();
} // otherwise ignore
- return false;
+ return true;
}
return false;
}
@@ -92,10 +116,52 @@ public class GenerateFragment extends Fragment {
Helper.showKeyboard(getActivity());
}
});
- etWalletPassword.addTextChangedListener(new TextWatcher() {
+ etWalletPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
+ etWalletMnemonic.requestFocus();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ etWalletMnemonic.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
+ if (etWalletMnemonic.length() == 0) {
+ etWalletAddress.requestFocus();
+ } else if (mnemonicOk()) {
+ etWalletRestoreHeight.requestFocus();
+ } else {
+ Toast.makeText(getActivity(), getString(R.string.generate_check_mnemonic), Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+ return false;
+ }
+ });
+ etWalletMnemonic.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Helper.showKeyboard(getActivity());
+ }
+ });
+ etWalletMnemonic.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
- showMnemonic("");
+ if (etWalletMnemonic.length() > 0) {
+ etWalletRestoreHeight.setVisibility(View.VISIBLE);
+ etWalletAddress.setVisibility(View.INVISIBLE);
+ } else {
+ etWalletAddress.setVisibility(View.VISIBLE);
+ if (etWalletAddress.length() == 0) {
+ etWalletRestoreHeight.setVisibility(View.INVISIBLE);
+ } else {
+ etWalletRestoreHeight.setVisibility(View.VISIBLE);
+ }
+
+ }
}
@Override
@@ -106,12 +172,103 @@ public class GenerateFragment extends Fragment {
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
- etWalletPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+
+ etWalletAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
+ if (etWalletAddress.length() == 0) {
+ Helper.hideKeyboard(getActivity());
+ generateWallet();
+ } else if (addressOk()) {
+ etWalletViewKey.requestFocus();
+ } else {
+ Toast.makeText(getActivity(), getString(R.string.generate_check_address), Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+ return false;
+ }
+ });
+ etWalletAddress.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Helper.showKeyboard(getActivity());
+ }
+ });
+ etWalletAddress.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void afterTextChanged(Editable editable) {
+ if (etWalletAddress.length() > 0) {
+ llRestoreKeys.setVisibility(View.VISIBLE);
+ etWalletMnemonic.setVisibility(View.INVISIBLE);
+ etWalletRestoreHeight.setVisibility(View.VISIBLE);
+ } else {
+ llRestoreKeys.setVisibility(View.INVISIBLE);
+ etWalletMnemonic.setVisibility(View.VISIBLE);
+ if (etWalletMnemonic.length() == 0) {
+ etWalletRestoreHeight.setVisibility(View.INVISIBLE);
+ } else {
+ etWalletRestoreHeight.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+ });
+
+ etWalletViewKey.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
+ if (viewKeyOk()) {
+ etWalletSpendKey.requestFocus();
+ } else {
+ Toast.makeText(getActivity(), getString(R.string.generate_check_key), Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+ return false;
+ }
+ });
+ etWalletViewKey.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Helper.showKeyboard(getActivity());
+ }
+ });
+
+ etWalletSpendKey.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
+ if (spendKeyOk()) {
+ Helper.hideKeyboard(getActivity());
+ generateWallet();
+ } else {
+ Toast.makeText(getActivity(), getString(R.string.generate_check_key), Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+ return false;
+ }
+ });
+ etWalletSpendKey.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Helper.showKeyboard(getActivity());
+ }
+ });
+
+ etWalletRestoreHeight.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
Helper.hideKeyboard(getActivity());
generateWallet();
- return false;
+ return true;
}
return false;
}
@@ -125,19 +282,29 @@ public class GenerateFragment extends Fragment {
}
});
- bAccept.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- acceptWallet();
- }
- });
-
- bAccept.setEnabled(false);
- llAccept.setVisibility(View.GONE);
-
return view;
}
+ private boolean mnemonicOk() {
+ String seed = etWalletMnemonic.getText().toString();
+ return (seed.split("\\s").length == 25); // 25 words
+ }
+
+ private boolean addressOk() {
+ String address = etWalletAddress.getText().toString();
+ return ((address.length() == 95) && ("49A".indexOf(address.charAt(0)) >= 0));
+ }
+
+ private boolean viewKeyOk() {
+ String viewKey = etWalletViewKey.getText().toString();
+ return (viewKey.length() == 64) && (viewKey.matches("^[0-9a-fA-F]+$"));
+ }
+
+ private boolean spendKeyOk() {
+ String spendKey = etWalletSpendKey.getText().toString();
+ return ((spendKey.length() == 0) || ((spendKey.length() == 64) && (spendKey.matches("^[0-9a-fA-F]+$"))));
+ }
+
private void generateWallet() {
String name = etWalletName.getText().toString();
if (name.length() == 0) return;
@@ -148,43 +315,56 @@ public class GenerateFragment extends Fragment {
return;
}
String password = etWalletPassword.getText().toString();
- bGenerate.setEnabled(false);
- activityCallback.onGenerate(name, password);
- }
- private void acceptWallet() {
- String name = etWalletName.getText().toString();
- String password = etWalletPassword.getText().toString();
- bAccept.setEnabled(false);
- activityCallback.onAccept(name, password);
- }
+ String seed = etWalletMnemonic.getText().toString();
+ String address = etWalletAddress.getText().toString();
- private void setGenerateEnabled() {
- bGenerate.setEnabled(etWalletName.length() > 0);
- }
-
- public void showMnemonic(String mnemonic) {
- setGenerateEnabled();
- if (mnemonic.length() > 0) {
- tvWalletMnemonic.setText(mnemonic);
- bAccept.setEnabled(true);
- llAccept.setVisibility(View.VISIBLE);
- } else {
- if (llAccept.getVisibility() != View.GONE) {
- tvWalletMnemonic.setText(getActivity().getString(R.string.generate_seed));
- bAccept.setEnabled(false);
- llAccept.setVisibility(View.GONE);
- }
+ long height;
+ try {
+ height = Long.parseLong(etWalletRestoreHeight.getText().toString());
+ } catch (NumberFormatException ex) {
+ Log.e(TAG, "Cannot parse " + etWalletRestoreHeight.getText().toString());
+ Log.e(TAG, ex.getLocalizedMessage());
+ height = 0; // Keep calm and carry on!
}
+
+ // figure out how we want to create this wallet
+ // A. from scratch
+ if ((seed.length() == 0) && (address.length() == 0)) {
+ bGenerate.setVisibility(View.INVISIBLE);
+ activityCallback.onGenerate(name, password);
+ } else
+ // B. from seed
+ if (mnemonicOk()) {
+ bGenerate.setVisibility(View.INVISIBLE);
+ activityCallback.onGenerate(name, password, seed, height);
+ } else
+ // C. from keys
+ if (addressOk() && viewKeyOk() && (spendKeyOk())) {
+ String viewKey = etWalletViewKey.getText().toString();
+ String spendKey = etWalletSpendKey.getText().toString();
+ bGenerate.setVisibility(View.INVISIBLE);
+ activityCallback.onGenerate(name, password, address, viewKey, spendKey, height);
+ } else
+ // D. none of the above :)
+ {
+ Toast.makeText(getActivity(), getString(R.string.generate_check_something), Toast.LENGTH_LONG).show();
+ }
+ }
+
+ public void walletGenerateError() {
+ bGenerate.setEnabled(etWalletName.length() > 0);
+ bGenerate.setVisibility(View.VISIBLE);
}
GenerateFragment.Listener activityCallback;
- // Container Activity must implement this interface
public interface Listener {
void onGenerate(String name, String password);
- void onAccept(String name, String password);
+ void onGenerate(String name, String password, String seed, long height);
+
+ void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
File getStorageRoot();
}
diff --git a/app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java b/app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java
new file mode 100644
index 0000000..38be477
--- /dev/null
+++ b/app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java
@@ -0,0 +1,116 @@
+/*
+ * 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;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.m2049r.xmrwallet.model.WalletManager;
+
+import java.text.NumberFormat;
+
+// TODO: somehow show which net we are generating for
+
+public class GenerateReviewFragment extends Fragment {
+ static final String TAG = "GenerateReviewFragment";
+
+ TextView tvWalletName;
+ TextView tvWalletPassword;
+ TextView tvWalletAddress;
+ TextView tvWalletMnemonic;
+ TextView tvWalletViewKey;
+ TextView tvWalletSpendKey;
+ Button bAccept;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View view = inflater.inflate(R.layout.gen_review_fragment, container, false);
+
+ tvWalletName = (TextView) view.findViewById(R.id.tvWalletName);
+ tvWalletPassword = (TextView) view.findViewById(R.id.tvWalletPassword);
+ tvWalletAddress = (TextView) view.findViewById(R.id.tvWalletAddress);
+ tvWalletViewKey = (TextView) view.findViewById(R.id.tvWalletViewKey);
+ tvWalletSpendKey = (TextView) view.findViewById(R.id.tvWalletSpendKey);
+ tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
+
+ bAccept = (Button) view.findViewById(R.id.bAccept);
+
+ boolean testnet = WalletManager.getInstance().isTestNet();
+ tvWalletMnemonic.setTextIsSelectable(testnet);
+
+ bAccept.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ acceptWallet();
+ }
+ });
+
+ showDetails();
+ return view;
+ }
+
+ private void acceptWallet() {
+ String name = tvWalletName.getText().toString();
+ String password = tvWalletPassword.getText().toString();
+ bAccept.setEnabled(false);
+ activityCallback.onAccept(name, password);
+ }
+
+ public void showDetails() {
+ Bundle b = getArguments();
+ String name = b.getString("name");
+ String password = b.getString("password");
+ String address = b.getString("address");
+ String seed = b.getString("seed");
+ String view = b.getString("viewkey");
+ String spend = b.getString("spendkey");
+ long height = b.getLong("restoreHeight");
+ tvWalletName.setText(name);
+ tvWalletPassword.setText(password);
+ tvWalletAddress.setText(address);
+ tvWalletMnemonic.setText(seed);
+ tvWalletViewKey.setText(view);
+ tvWalletSpendKey.setText(spend);
+ NumberFormat formatter = NumberFormat.getInstance();
+ bAccept.setEnabled(true);
+ }
+
+ GenerateReviewFragment.Listener activityCallback;
+
+ public interface Listener {
+ void onAccept(String name, String password);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof GenerateReviewFragment.Listener) {
+ this.activityCallback = (GenerateReviewFragment.Listener) context;
+ } else {
+ throw new ClassCastException(context.toString()
+ + " must implement Listener");
+ }
+ }
+}
diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java
index b9becc4..0d3d76d 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java
@@ -19,6 +19,7 @@ package com.m2049r.xmrwallet;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
+import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.DialogInterface;
@@ -31,9 +32,7 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
@@ -46,7 +45,7 @@ import com.m2049r.xmrwallet.util.Helper;
import java.io.File;
public class LoginActivity extends Activity
- implements LoginFragment.Listener, GenerateFragment.Listener {
+ implements LoginFragment.Listener, GenerateFragment.Listener, GenerateReviewFragment.Listener {
static final String TAG = "LoginActivity";
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
@@ -219,14 +218,22 @@ public class LoginActivity extends Activity
}
void startGenerateFragment() {
- replaceFragment(new GenerateFragment());
+ replaceFragment(new GenerateFragment(), "gen", null);
Log.d(TAG, "GenerateFragment placed");
}
- void replaceFragment(Fragment newFragment) {
+ void startReviewFragment(Bundle extras) {
+ replaceFragment(new GenerateReviewFragment(), null, extras);
+ Log.d(TAG, "GenerateReviewFragment placed");
+ }
+
+ void replaceFragment(Fragment newFragment, String name, Bundle extras) {
+ if (extras != null) {
+ newFragment.setArguments(extras);
+ }
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
- transaction.addToBackStack(null);
+ transaction.addToBackStack(name);
transaction.commit();
}
@@ -235,33 +242,33 @@ public class LoginActivity extends Activity
//////////////////////////////////////////
static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more
- @Override
- public void onGenerate(final String name, final String password) {
+ public void createWallet(final String name, final String password, final WalletCreator walletCreator) {
final GenerateFragment genFragment = (GenerateFragment)
getFragmentManager().findFragmentById(R.id.fragment_container);
File newWalletFolder = new File(getStorageRoot(), ".new");
if (!newWalletFolder.exists()) {
if (!newWalletFolder.mkdir()) {
Log.e(TAG, "Cannot create new wallet dir " + newWalletFolder.getAbsolutePath());
- genFragment.showMnemonic("");
+ genFragment.walletGenerateError();
return;
}
}
if (!newWalletFolder.isDirectory()) {
Log.e(TAG, "New wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
- genFragment.showMnemonic("");
+ genFragment.walletGenerateError();
return;
}
- File cache = new File(newWalletFolder, name);
- cache.delete();
- File keys = new File(newWalletFolder, name + ".keys");
- keys.delete();
- File address = new File(newWalletFolder, name + ".address.txt");
- address.delete();
+ File cacheFile = new File(newWalletFolder, name);
+ cacheFile.delete();
+ File keysFile = new File(newWalletFolder, name + ".keys");
+ keysFile.delete();
+ final File addressFile = new File(newWalletFolder, name + ".address.txt");
+ addressFile.delete();
- if (cache.exists() || keys.exists() || address.exists()) {
- Log.e(TAG, "Cannot remove all old wallet files: " + cache.getAbsolutePath());
- genFragment.showMnemonic("");
+ if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) {
+ Log.e(TAG, "Cannot remove all old wallet files: " + cacheFile.getAbsolutePath());
+ genFragment.walletGenerateError();
+ ;
return;
}
@@ -271,17 +278,25 @@ public class LoginActivity extends Activity
@Override
public void run() {
Log.d(TAG, "creating wallet " + newWalletPath);
- Wallet newWallet = WalletManager.getInstance()
- .createWallet(newWalletPath, password, MNEMONIC_LANGUAGE);
- Log.d(TAG, "wallet created");
- Log.d(TAG, "Created " + newWallet.getAddress());
- Log.d(TAG, "Seed " + newWallet.getSeed() + ".");
- final String mnemonic = newWallet.getSeed();
+ Wallet newWallet = walletCreator.createWallet(newWalletPath, password);
+ final String seed = newWallet.getSeed();
+ final String address = newWallet.getAddress();
+ final String view = newWallet.getSecretViewKey();
+ final long height = newWallet.getBlockChainHeight();
+ final String spend = "not available - use seed for recovery"; //TODO
newWallet.close();
+ Log.d(TAG, "Created " + address);
runOnUiThread(new Runnable() {
public void run() {
- if (genFragment.isAdded())
- genFragment.showMnemonic(mnemonic);
+ Bundle b = new Bundle();
+ b.putString("name", name);
+ b.putString("password", password);
+ b.putString("seed", seed);
+ b.putString("address", address);
+ b.putString("viewkey", view);
+ b.putString("spendkey", spend);
+ b.putLong("restoreHeight", height);
+ startReviewFragment(b);
}
});
}
@@ -289,10 +304,54 @@ public class LoginActivity extends Activity
, "CreateWallet", MoneroHandlerThread.THREAD_STACK_SIZE).start();
}
+ interface WalletCreator {
+ Wallet createWallet(String path, String password);
+ }
+
+ @Override
+ public void onGenerate(String name, String password) {
+ createWallet(name, password,
+ new WalletCreator() {
+ public Wallet createWallet(String path, String password) {
+ return WalletManager.getInstance()
+ .createWallet(path, password, MNEMONIC_LANGUAGE);
+
+ }
+ });
+ }
+
+ @Override
+ public void onGenerate(String name, String password, final String seed, final long restoreHeight) {
+ createWallet(name, password,
+ new WalletCreator() {
+ public Wallet createWallet(String path, String password) {
+ Wallet newWallet = WalletManager.getInstance().recoveryWallet(path, seed, restoreHeight);
+ newWallet.setPassword(password);
+ newWallet.store();
+ return newWallet;
+ }
+ });
+ }
+
+ @Override
+ public void onGenerate(String name, String password,
+ final String address, final String viewKey, final String spendKey, final long restoreHeight) {
+ createWallet(name, password,
+ new WalletCreator() {
+ public Wallet createWallet(String path, String password) {
+ Wallet newWallet = WalletManager.getInstance()
+ .createWalletFromKeys(path, MNEMONIC_LANGUAGE, restoreHeight,
+ address, viewKey, spendKey);
+ newWallet.setPassword(password);
+ newWallet.store();
+ return newWallet;
+ }
+ });
+ }
+
+
@Override
public void onAccept(final String name, final String password) {
- final GenerateFragment genFragment = (GenerateFragment)
- getFragmentManager().findFragmentById(R.id.fragment_container);
File newWalletFolder = new File(getStorageRoot(), ".new");
if (!newWalletFolder.isDirectory()) {
Log.e(TAG, "New wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
@@ -327,8 +386,8 @@ public class LoginActivity extends Activity
runOnUiThread(new Runnable() {
public void run() {
if (rc) {
- if (genFragment.isAdded())
- getFragmentManager().popBackStack();
+ getFragmentManager().popBackStack("gen",
+ FragmentManager.POP_BACK_STACK_INCLUSIVE);
Toast.makeText(LoginActivity.this,
getString(R.string.generate_wallet_created), Toast.LENGTH_SHORT).show();
} else {
diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
index 3ab58db..ae05a40 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
@@ -193,7 +193,7 @@ public class LoginFragment extends Fragment {
displayedList.clear();
String x = isMainNet() ? "4" : "9A";
for (String s : walletList) {
- Log.d(TAG, "filtering " + s);
+ // Log.d(TAG, "filtering " + s);
if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s);
}
displayedList.add(WALLETNAME_PREAMBLE + getString(R.string.generate_title));
@@ -206,7 +206,7 @@ public class LoginFragment extends Fragment {
walletList.clear();
for (WalletManager.WalletInfo walletInfo : walletInfos) {
- Log.d(TAG, walletInfo.address);
+ // Log.d(TAG, walletInfo.address);
String displayAddress = walletInfo.address;
if (displayAddress.length() == 95) {
displayAddress = walletInfo.address.substring(0, 6);
diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
index ee4a636..c708b3c 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
@@ -37,11 +37,13 @@ import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Wallet;
+import java.text.NumberFormat;
import java.util.List;
public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener {
private static final String TAG = "WalletFragment";
private TransactionInfoAdapter adapter;
+ private NumberFormat formatter = NumberFormat.getInstance();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -171,7 +173,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
long daemonHeight = activityCallback.getDaemonHeight();
if (!wallet.isSynchronized()) {
long n = daemonHeight - wallet.getBlockChainHeight();
- sync = n + " " + getString(R.string.status_remaining);
+ sync = formatter.format(n) + " " + getString(R.string.status_remaining);
if (firstBlock == 0) {
firstBlock = wallet.getBlockChainHeight();
}
@@ -180,7 +182,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
if (x == 0) x = -1;
onProgress(x);
} else {
- sync = getString(R.string.status_synced) + ": " + wallet.getBlockChainHeight();
+ sync = getString(R.string.status_synced) + ": " + formatter.format(wallet.getBlockChainHeight());
}
}
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
diff --git a/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java b/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java
index 54782cf..357027b 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java
@@ -78,6 +78,8 @@ public class WalletManager {
return wallet;
}
+ private native long createWalletJ(String path, String password, String language, boolean isTestNet);
+
public Wallet openWallet(String path, String password) {
long walletHandle = openWalletJ(path, password, isTestNet());
Wallet wallet = new Wallet(walletHandle);
@@ -85,6 +87,8 @@ public class WalletManager {
return wallet;
}
+ private native long openWalletJ(String path, String password, boolean isTestNet);
+
public Wallet recoveryWallet(String path, String mnemonic) {
Wallet wallet = recoveryWallet(path, mnemonic, 0);
manageWallet(wallet.getName(), wallet);
@@ -98,12 +102,17 @@ public class WalletManager {
return wallet;
}
- private native long createWalletJ(String path, String password, String language, boolean isTestNet);
-
- private native long openWalletJ(String path, String password, boolean isTestNet);
-
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
+ public Wallet createWalletFromKeys(String path, String language, long restoreHeight,
+ String addressString, String viewKeyString, String spendKeyString) {
+ long walletHandle = createWalletFromKeysJ(path, language, isTestNet(), restoreHeight,
+ addressString, viewKeyString, spendKeyString);
+ Wallet wallet = new Wallet(walletHandle);
+ manageWallet(wallet.getName(), wallet);
+ return wallet;
+ }
+
private native long createWalletFromKeysJ(String path, String language,
boolean isTestNet,
long restoreHeight,
diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
index b40f3a8..f67ab9b 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
@@ -419,6 +419,7 @@ public class WalletService extends Service {
WalletManager.getInstance().close(wallet); // TODO close() failed?
wallet = null;
// TODO what do we do with the progress??
+ // TODO tell the activity this failed
}
}
return wallet;
diff --git a/app/src/main/res/layout/gen_fragment.xml b/app/src/main/res/layout/gen_fragment.xml
index e0ed6a9..2fcf115 100644
--- a/app/src/main/res/layout/gen_fragment.xml
+++ b/app/src/main/res/layout/gen_fragment.xml
@@ -2,108 +2,121 @@
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
-
+ android:orientation="horizontal"
+ android:weightSum="2">
+
+
+
+
+
+ android:scrollHorizontally="false"
+ android:textAlignment="center"
+ android:textSize="16sp" />
+ android:textAlignment="center"
+ android:textSize="16sp" />
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+ android:text="@string/generate_button_reset" />
+ -->
diff --git a/app/src/main/res/layout/gen_review_fragment.xml b/app/src/main/res/layout/gen_review_fragment.xml
new file mode 100644
index 0000000..816143a
--- /dev/null
+++ b/app/src/main/res/layout/gen_review_fragment.xml
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/login_fragment.xml b/app/src/main/res/layout/login_fragment.xml
index 5090c92..8ae9995 100644
--- a/app/src/main/res/layout/login_fragment.xml
+++ b/app/src/main/res/layout/login_fragment.xml
@@ -1,5 +1,5 @@
+
+ android:paddingTop="@dimen/activity_vertical_margin">
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 09cfd3b..6f27b22 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -46,16 +46,41 @@
We really need those External Storage permissions!
Generate Wallet
- Wallet Name
- Wallet Password
+ Wallet Name
+ Wallet Password
Do it already!
Mnemonic Seed
- I have noted this mnemonic seed\nNow, I want to loose all my money!
+ I have noted the mnemonic seed\nNow, I want to loose all my money!
+ I\'m confused - Let me start again!
+
Wallet exists! Choose another name
Wallet created
Wallet create failed (1/2)
Wallet create failed (2/2)
9tDC52GsMjTNt4dpnRCwAF7ekVBkbkgkXGaMKTcSTpBhGpqkPX56jCNRydLq9oGjbbAQBsZhLfgmTKsntmxRd3TaJFYM2f8
+ e2b99f4cc3d644774c4b118db05f8aa9967583a01ca4d47058c3860af10bd306
+ 300a54208ab0a638a8407a12e3de946da76f5a9ded303338452332ec7755210d
camp feline inflamed memoir afloat eight alerts females gutter cogs menu waveform gather tawny judge gusts yahoo doctor females biscuit alchemy reef agony austere camp
+ 1307882
+
+ Public Address (optional)
+ View Key
+ Spend Key (optional)
+ Mnemonic Seed (optional)
+ Restore Height (optional)
+
+ Wallet
+ Password
+ Public Address
+ View Key
+ Spend Key
+ Mnemonic Seed
+ Restore Height:
+
+ Check your keys!
+ Check your key!
+ Check your address!
+ Check your mnemonic seed!
+ Check your entry!