|
|
|
/*
|
|
|
|
* 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.content.Context;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.support.annotation.Nullable;
|
|
|
|
import android.support.design.widget.TextInputLayout;
|
|
|
|
import android.support.v4.app.Fragment;
|
|
|
|
import android.text.InputType;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.KeyEvent;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuInflater;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import android.widget.Button;
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
|
|
|
import com.m2049r.xmrwallet.layout.Toolbar;
|
|
|
|
import com.m2049r.xmrwallet.model.Wallet;
|
|
|
|
import com.m2049r.xmrwallet.model.WalletManager;
|
|
|
|
import com.m2049r.xmrwallet.util.Helper;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
|
|
public class GenerateFragment extends Fragment {
|
|
|
|
static final String TAG = "GenerateFragment";
|
|
|
|
|
|
|
|
static final String TYPE = "type";
|
|
|
|
static final String TYPE_NEW = "new";
|
|
|
|
static final String TYPE_KEY = "key";
|
|
|
|
static final String TYPE_SEED = "seed";
|
|
|
|
static final String TYPE_VIEWONLY = "view";
|
|
|
|
|
|
|
|
private TextInputLayout etWalletName;
|
|
|
|
private TextInputLayout etWalletPassword;
|
|
|
|
private TextInputLayout etWalletAddress;
|
|
|
|
private TextInputLayout etWalletMnemonic;
|
|
|
|
private TextInputLayout etWalletViewKey;
|
|
|
|
private TextInputLayout etWalletSpendKey;
|
|
|
|
private TextInputLayout etWalletRestoreHeight;
|
|
|
|
private Button bGenerate;
|
|
|
|
|
|
|
|
private String type = null;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
|
|
Bundle savedInstanceState) {
|
|
|
|
|
|
|
|
Bundle args = getArguments();
|
|
|
|
this.type = args.getString(TYPE);
|
|
|
|
|
|
|
|
View view = inflater.inflate(R.layout.fragment_generate, container, false);
|
|
|
|
|
|
|
|
etWalletName = (TextInputLayout) view.findViewById(R.id.etWalletName);
|
|
|
|
etWalletPassword = (TextInputLayout) view.findViewById(R.id.etWalletPassword);
|
|
|
|
etWalletMnemonic = (TextInputLayout) view.findViewById(R.id.etWalletMnemonic);
|
|
|
|
etWalletAddress = (TextInputLayout) view.findViewById(R.id.etWalletAddress);
|
|
|
|
etWalletViewKey = (TextInputLayout) view.findViewById(R.id.etWalletViewKey);
|
|
|
|
etWalletSpendKey = (TextInputLayout) view.findViewById(R.id.etWalletSpendKey);
|
|
|
|
etWalletRestoreHeight = (TextInputLayout) view.findViewById(R.id.etWalletRestoreHeight);
|
|
|
|
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
|
|
|
|
|
|
|
etWalletMnemonic.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT);
|
|
|
|
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
|
|
|
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
|
|
|
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
|
|
|
|
|
|
|
etWalletName.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
|
|
@Override
|
|
|
|
public void onFocusChange(View v, boolean hasFocus) {
|
|
|
|
if (!hasFocus) {
|
|
|
|
checkName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
etWalletMnemonic.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
|
|
@Override
|
|
|
|
public void onFocusChange(View v, boolean hasFocus) {
|
|
|
|
if (!hasFocus) {
|
|
|
|
checkMnemonic();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
etWalletAddress.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
|
|
@Override
|
|
|
|
public void onFocusChange(View v, boolean hasFocus) {
|
|
|
|
if (!hasFocus) {
|
|
|
|
checkAddress();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
etWalletViewKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
|
|
@Override
|
|
|
|
public void onFocusChange(View v, boolean hasFocus) {
|
|
|
|
if (!hasFocus) {
|
|
|
|
checkViewKey();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
etWalletSpendKey.getEditText().setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
|
|
@Override
|
|
|
|
public void onFocusChange(View v, boolean hasFocus) {
|
|
|
|
if (!hasFocus) {
|
|
|
|
checkSpendKey();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Helper.showKeyboard(getActivity());
|
|
|
|
//##############
|
|
|
|
etWalletName.getEditText().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 (checkName()) {
|
|
|
|
etWalletPassword.requestFocus();
|
|
|
|
} // otherwise ignore
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (type.equals(TYPE_NEW)) {
|
|
|
|
etWalletPassword.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE);
|
|
|
|
etWalletPassword.getEditText().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)) {
|
|
|
|
Helper.hideKeyboard(getActivity());
|
|
|
|
generateWallet();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if (type.equals(TYPE_SEED)) {
|
|
|
|
etWalletPassword.getEditText().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.setVisibility(View.VISIBLE);
|
|
|
|
etWalletMnemonic.getEditText().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 (checkMnemonic()) {
|
|
|
|
etWalletRestoreHeight.requestFocus();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if (type.equals(TYPE_KEY) || type.equals(TYPE_VIEWONLY)) {
|
|
|
|
etWalletPassword.getEditText().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)) {
|
|
|
|
etWalletAddress.requestFocus();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
etWalletAddress.setVisibility(View.VISIBLE);
|
|
|
|
etWalletAddress.getEditText().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 (checkAddress()) {
|
|
|
|
etWalletViewKey.requestFocus();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
etWalletViewKey.setVisibility(View.VISIBLE);
|
|
|
|
etWalletViewKey.getEditText().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 (checkViewKey()) {
|
|
|
|
if (type.equals(TYPE_KEY)) {
|
|
|
|
etWalletSpendKey.requestFocus();
|
|
|
|
} else {
|
|
|
|
etWalletRestoreHeight.requestFocus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (type.equals(TYPE_KEY)) {
|
|
|
|
etWalletSpendKey.setVisibility(View.VISIBLE);
|
|
|
|
etWalletSpendKey.getEditText().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 (checkSpendKey()) {
|
|
|
|
etWalletRestoreHeight.requestFocus();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!type.equals(TYPE_NEW)) {
|
|
|
|
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
|
|
|
etWalletRestoreHeight.getEditText().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)) {
|
|
|
|
Helper.hideKeyboard(getActivity());
|
|
|
|
generateWallet();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
bGenerate.setOnClickListener(new View.OnClickListener()
|
|
|
|
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
|
|
|
Helper.hideKeyboard(getActivity());
|
|
|
|
generateWallet();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
etWalletName.requestFocus();
|
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean checkName() {
|
|
|
|
String name = etWalletName.getEditText().getText().toString();
|
|
|
|
boolean ok = true;
|
|
|
|
if (name.length() == 0) {
|
|
|
|
etWalletName.setError(getString(R.string.generate_wallet_name));
|
|
|
|
ok = false;
|
|
|
|
} else if (name.charAt(0) == '.') {
|
|
|
|
etWalletName.setError(getString(R.string.generate_wallet_dot));
|
|
|
|
ok = false;
|
|
|
|
} else {
|
|
|
|
File walletFile = Helper.getWalletFile(getActivity(), name);
|
|
|
|
if (WalletManager.getInstance().walletExists(walletFile)) {
|
|
|
|
etWalletName.setError(getString(R.string.generate_wallet_exists));
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok) {
|
|
|
|
etWalletName.setError(null);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean checkMnemonic() {
|
|
|
|
String seed = etWalletMnemonic.getEditText().getText().toString();
|
|
|
|
boolean ok = (seed.split("\\s").length == 25); // 25 words
|
|
|
|
if (!ok) {
|
|
|
|
etWalletMnemonic.setError(getString(R.string.generate_check_mnemonic));
|
|
|
|
} else {
|
|
|
|
etWalletMnemonic.setError(null);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean checkAddress() {
|
|
|
|
String address = etWalletAddress.getEditText().getText().toString();
|
|
|
|
boolean ok = Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
|
|
|
|
if (!ok) {
|
|
|
|
etWalletAddress.setError(getString(R.string.generate_check_address));
|
|
|
|
} else {
|
|
|
|
etWalletAddress.setError(null);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean checkViewKey() {
|
|
|
|
String viewKey = etWalletViewKey.getEditText().getText().toString();
|
|
|
|
boolean ok = (viewKey.length() == 64) && (viewKey.matches("^[0-9a-fA-F]+$"));
|
|
|
|
if (!ok) {
|
|
|
|
etWalletViewKey.setError(getString(R.string.generate_check_key));
|
|
|
|
} else {
|
|
|
|
etWalletViewKey.setError(null);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean checkSpendKey() {
|
|
|
|
String spendKey = etWalletSpendKey.getEditText().getText().toString();
|
|
|
|
boolean ok = ((spendKey.length() == 0) || ((spendKey.length() == 64) && (spendKey.matches("^[0-9a-fA-F]+$"))));
|
|
|
|
if (!ok) {
|
|
|
|
etWalletSpendKey.setError(getString(R.string.generate_check_key));
|
|
|
|
} else {
|
|
|
|
etWalletSpendKey.setError(null);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void generateWallet() {
|
|
|
|
if (!checkName()) return;
|
|
|
|
String name = etWalletName.getEditText().getText().toString();
|
|
|
|
String password = etWalletPassword.getEditText().getText().toString();
|
|
|
|
|
|
|
|
long height;
|
|
|
|
try {
|
|
|
|
height = Long.parseLong(etWalletRestoreHeight.getEditText().getText().toString());
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
height = 0; // Keep calm and carry on!
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type.equals(TYPE_NEW)) {
|
|
|
|
bGenerate.setEnabled(false);
|
|
|
|
activityCallback.onGenerate(name, password);
|
|
|
|
} else if (type.equals(TYPE_SEED)) {
|
|
|
|
if (!checkMnemonic()) return;
|
|
|
|
String seed = etWalletMnemonic.getEditText().getText().toString();
|
|
|
|
bGenerate.setEnabled(false);
|
|
|
|
activityCallback.onGenerate(name, password, seed, height);
|
|
|
|
} else if (type.equals(TYPE_KEY) || type.equals(TYPE_VIEWONLY)) {
|
|
|
|
if (checkAddress() && checkViewKey() && checkSpendKey()) {
|
|
|
|
bGenerate.setEnabled(false);
|
|
|
|
String address = etWalletAddress.getEditText().getText().toString();
|
|
|
|
String viewKey = etWalletViewKey.getEditText().getText().toString();
|
|
|
|
String spendKey = "";
|
|
|
|
if (type.equals(TYPE_KEY)) {
|
|
|
|
spendKey = etWalletSpendKey.getEditText().getText().toString();
|
|
|
|
}
|
|
|
|
activityCallback.onGenerate(name, password, address, viewKey, spendKey, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void walletGenerateError() {
|
|
|
|
bGenerate.setEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
Log.d(TAG, "onResume()");
|
|
|
|
activityCallback.setTitle(getString(R.string.generate_title) + " - " + getType());
|
|
|
|
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
String getType() {
|
|
|
|
switch (type) {
|
|
|
|
case TYPE_KEY:
|
|
|
|
return getString(R.string.generate_wallet_type_key);
|
|
|
|
case TYPE_NEW:
|
|
|
|
return getString(R.string.generate_wallet_type_new);
|
|
|
|
case TYPE_SEED:
|
|
|
|
return getString(R.string.generate_wallet_type_seed);
|
|
|
|
case TYPE_VIEWONLY:
|
|
|
|
return getString(R.string.generate_wallet_type_view);
|
|
|
|
default:
|
|
|
|
Log.e(TAG, "unknown type " + type);
|
|
|
|
return "?";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GenerateFragment.Listener activityCallback;
|
|
|
|
|
|
|
|
public interface Listener {
|
|
|
|
void onGenerate(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);
|
|
|
|
|
|
|
|
void setTitle(String title);
|
|
|
|
|
|
|
|
void setToolbarButton(int type);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAttach(Context context) {
|
|
|
|
super.onAttach(context);
|
|
|
|
if (context instanceof GenerateFragment.Listener) {
|
|
|
|
this.activityCallback = (GenerateFragment.Listener) context;
|
|
|
|
} else {
|
|
|
|
throw new ClassCastException(context.toString()
|
|
|
|
+ " must implement Listener");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
setHasOptionsMenu(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
|
|
|
switch (type) {
|
|
|
|
case TYPE_KEY:
|
|
|
|
inflater.inflate(R.menu.create_wallet_keys, menu);
|
|
|
|
break;
|
|
|
|
case TYPE_NEW:
|
|
|
|
inflater.inflate(R.menu.create_wallet_new, menu);
|
|
|
|
break;
|
|
|
|
case TYPE_SEED:
|
|
|
|
inflater.inflate(R.menu.create_wallet_seed, menu);
|
|
|
|
break;
|
|
|
|
case TYPE_VIEWONLY:
|
|
|
|
inflater.inflate(R.menu.create_wallet_view, menu);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
super.onCreateOptionsMenu(menu, inflater);
|
|
|
|
}
|
|
|
|
}
|