# Conflicts:
#	app/src/main/java/cy/agorise/crystalwallet/activities/ImportSeedActivity.java
This commit is contained in:
Javier Varona 2018-10-24 23:07:11 -04:00
commit c216dfa209
15 changed files with 304 additions and 211 deletions

View file

@ -259,52 +259,7 @@ class CreateSeedActivity : CustomActivity() {
* */ * */
if (result) { if (result) {
/*
* Show the dialog for connection with the server
* */
val creatingAccountMaterialDialog = CrystalDialog(globalActivity)
creatingAccountMaterialDialog.setText(globalActivity.resources.getString(R.string.window_create_seed_Server_validation))
creatingAccountMaterialDialog.progress()
creatingAccountMaterialDialog.show()
/*
* Validate the account does not exists
* */
val request = ValidateExistBitsharesAccountRequest(tietAccountName?.text.toString())
request.setListener {
/*
* Dismiss the dialog of loading
* */
creatingAccountMaterialDialog.dismiss()
if (request.accountExists) {
/*
* The account exists and is not valid
* */
tietAccountName.fieldValidatorModel.setInvalid()
tietAccountName.fieldValidatorModel.message = tietAccountName.resources.getString(R.string.account_name_already_exist)
/*
* Disaible button create
* */
disableCreate()
} else {
/*
* Passed all validations
* */
tietAccountName.fieldValidatorModel.setValid()
/*
* Enable button create
* */
enableCreate() enableCreate()
}
}
CryptoNetInfoRequests.getInstance().addRequest(request)
} else { } else {

View file

@ -3,7 +3,6 @@ package cy.agorise.crystalwallet.activities;
import android.app.Activity; import android.app.Activity;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.Editable; import android.text.Editable;
@ -12,7 +11,6 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.thekhaeng.pushdownanim.PushDownAnim; import com.thekhaeng.pushdownanim.PushDownAnim;
@ -23,7 +21,6 @@ import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.OnTextChanged; import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R; import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.application.CrystalSecurityMonitor;
import cy.agorise.crystalwallet.dialogs.material.CrystalLoading; import cy.agorise.crystalwallet.dialogs.material.CrystalLoading;
import cy.agorise.crystalwallet.dialogs.material.DialogMaterial; import cy.agorise.crystalwallet.dialogs.material.DialogMaterial;
import cy.agorise.crystalwallet.dialogs.material.NegativeResponse; import cy.agorise.crystalwallet.dialogs.material.NegativeResponse;
@ -32,7 +29,6 @@ import cy.agorise.crystalwallet.dialogs.material.QuestionDialog;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests;
import cy.agorise.crystalwallet.requestmanagers.ImportBitsharesAccountRequest; import cy.agorise.crystalwallet.requestmanagers.ImportBitsharesAccountRequest;
import cy.agorise.crystalwallet.requestmanagers.ValidateImportBitsharesAccountRequest;
import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel; import cy.agorise.crystalwallet.viewmodels.AccountSeedViewModel;
import cy.agorise.crystalwallet.viewmodels.validators.ImportSeedValidator; import cy.agorise.crystalwallet.viewmodels.validators.ImportSeedValidator;
import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener; import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener;
@ -78,6 +74,11 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
final Activity activity = this; final Activity activity = this;
/*
* Flag to check correct PIN equality
* */
private boolean pinsOK = false;
@ -128,20 +129,20 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
/*
* Validate that PINs are equals
* */
validatePINS();
/* /*
* If all is ready to continue enable the button, contrarie case disable it * If all is ready to continue enable the button, contrarie case disable it
* */ * */
if(allFieldsAreFill()){ if(allFieldsAreOK()){
enableCreate(); enableCreate();
} }
else{ else{
disableCreate(); disableCreate();
} }
/*
* Validate that PINs are equals
* */
validatePINS();
} }
}); });
etPinConfirmation.addTextChangedListener(new TextWatcher() { etPinConfirmation.addTextChangedListener(new TextWatcher() {
@ -158,20 +159,20 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
/*
* Validate that PINs are equals
* */
validatePINS();
/* /*
* If all is ready to continue enable the button, contrarie case disable it * If all is ready to continue enable the button, contrarie case disable it
* */ * */
if(allFieldsAreFill()){ if(allFieldsAreOK()){
enableCreate(); enableCreate();
} }
else{ else{
disableCreate(); disableCreate();
} }
/*
* Validate that PINs are equals
* */
validatePINS();
} }
}); });
etSeedWords.addTextChangedListener(new TextWatcher() { etSeedWords.addTextChangedListener(new TextWatcher() {
@ -188,10 +189,15 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
/*
* Validate that PINs are equals
* */
validatePINS();
/* /*
* If all is ready to continue enable the button, contrarie case disable it * If all is ready to continue enable the button, contrarie case disable it
* */ * */
if(allFieldsAreFill()){ if(allFieldsAreOK()){
enableCreate(); enableCreate();
} }
else{ else{
@ -201,7 +207,7 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
/* /*
* Hide error field * Hide error field
* */ * */
txtErrorAccount.setVisibility(View.INVISIBLE); clearErrors();
} }
}); });
/* /*
@ -219,10 +225,15 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
//
// Validate that PINs are equals
//
validatePINS();
// //
// If all is ready to continue enable the button, contrarie case disable it // If all is ready to continue enable the button, contrarie case disable it
// //
if(allFieldsAreFill()){ if(allFieldsAreOK()){
enableCreate(); enableCreate();
} }
else{ else{
@ -237,6 +248,13 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
importSeedValidator.setListener(this); importSeedValidator.setListener(this);
} }
private void clearErrors(){
txtErrorPIN.setVisibility(View.INVISIBLE);
txtErrorAccount.setVisibility(View.INVISIBLE);
}
/* /*
* Validate that PINs are equals * Validate that PINs are equals
* */ * */
@ -246,30 +264,35 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
final String confirmoPIN = etPinConfirmation.getText().toString().trim(); final String confirmoPIN = etPinConfirmation.getText().toString().trim();
if(!pin.isEmpty() && !confirmoPIN.isEmpty()){ if(!pin.isEmpty() && !confirmoPIN.isEmpty()){
if(pin.compareTo(confirmoPIN)!=0){ if(pin.compareTo(confirmoPIN)!=0){
pinsOK = false;
txtErrorPIN.setVisibility(View.VISIBLE); txtErrorPIN.setVisibility(View.VISIBLE);
} }
else{ else{
txtErrorPIN.setVisibility(View.INVISIBLE); pinsOK = true;
clearErrors();
} }
} }
else{ else{
txtErrorPIN.setVisibility(View.INVISIBLE); pinsOK = false;
clearErrors();
} }
} }
/* /*
* Method to validate if all the fields are fill * Method to validate if all the fields are fill and correctly
* */ * */
private boolean allFieldsAreFill(){ private boolean allFieldsAreOK(){
boolean complete = false; boolean complete = false;
if( etPin.getText().toString().trim().compareTo("")!=0 && if( etPin.getText().toString().trim().compareTo("")!=0 &&
etPinConfirmation.getText().toString().trim().compareTo("")!=0 && etPinConfirmation.getText().toString().trim().compareTo("")!=0 &&
etSeedWords.getText().toString().trim().compareTo("")!=0 /*&& etSeedWords.getText().toString().trim().compareTo("")!=0 /*&&
etAccountName.getText().toString().trim().compareTo("")!=0*/){ etAccountName.getText().toString().trim().compareTo("")!=0*/){
if(pinsOK){
complete = true; complete = true;
} }
}
return complete; return complete;
} }
@ -327,6 +350,11 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
final CrystalLoading crystalLoading = new CrystalLoading(activity); final CrystalLoading crystalLoading = new CrystalLoading(activity);
crystalLoading.show(); crystalLoading.show();
/*
* Final service connection
* */
finalStep(crystalLoading);
/* /*
* Validate mnemonic with the server * Validate mnemonic with the server
* */ * */
@ -334,13 +362,10 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
request.setListener(new CryptoNetInfoRequestListener() { request.setListener(new CryptoNetInfoRequestListener() {
@Override @Override
public void onCarryOut() { public void onCarryOut() {
if(request.getStatus().equals(ValidateImportBitsharesAccountRequest.StatusCode.SUCCEEDED)){ if(request.getStatus().equals(ImportBitsharesAccountRequest.StatusCode.SUCCEEDED)){
//Correct //Correct
/*
* Final service connection
* */
finalStep(crystalLoading); finalStep(crystalLoading);
} }
@ -380,27 +405,58 @@ public class ImportSeedActivity extends AppCompatActivity implements UIValidator
* */ * */
crystalLoading.dismiss(); crystalLoading.dismiss();
if (!validatorRequest.getStatus().equals(ValidateImportBitsharesAccountRequest.StatusCode.SUCCEEDED)) { if (!validatorRequest.getStatus().equals(ImportBitsharesAccountRequest.StatusCode.SUCCEEDED)) {
String errorText = "An error ocurred attempting to import the account";
switch (validatorRequest.getStatus()){ switch (validatorRequest.getStatus()){
case PETITION_FAILED: case PETITION_FAILED:
case NO_INTERNET: case NO_INTERNET:
case NO_SERVER_CONNECTION: case NO_SERVER_CONNECTION:
errorText = "There was an error with the connection. Try again later"; activity.runOnUiThread(new Runnable() {
@Override
public void run() {
txtErrorAccount.setText(activity.getResources().getString(R.string.NO_SERVER_CONNECTION));
}
});
break; break;
case ACCOUNT_DOESNT_EXIST: case ACCOUNT_DOESNT_EXIST:
errorText = "The account doesn't exists"; activity.runOnUiThread(new Runnable() {
@Override
public void run() {
txtErrorAccount.setText(activity.getResources().getString(R.string.ACCOUNT_DOESNT_EXIST));
}
});
break; break;
case BAD_SEED: case BAD_SEED:
errorText = "The seed is not valid"; activity.runOnUiThread(new Runnable() {
@Override
public void run() {
txtErrorAccount.setText(activity.getResources().getString(R.string.BAD_SEED));
}
});
break; break;
case NO_ACCOUNT_DATA: case NO_ACCOUNT_DATA:
errorText = "The account doesn't have any data"; activity.runOnUiThread(new Runnable() {
@Override
public void run() {
txtErrorAccount.setText(activity.getResources().getString(R.string.NO_ACCOUNT_DATA));
}
});
break; break;
default:
txtErrorAccount.setText(activity.getResources().getString(R.string.ERROR_UNRECOGNIZABLE));
} }
Toast.makeText(thisActivity.getApplicationContext(),errorText,Toast.LENGTH_LONG).show(); activity.runOnUiThread(new Runnable() {
@Override
public void run() {
txtErrorAccount.setVisibility(View.VISIBLE);
}
});
//Toast.makeText(thisActivity.getApplicationContext(),errorText,Toast.LENGTH_LONG).show();
} else { } else {
Intent intent = new Intent(thisActivity, BoardActivity.class); Intent intent = new Intent(thisActivity, BoardActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

View file

@ -36,6 +36,19 @@ public class PatternRequestActivity extends AppCompatActivity {
@BindView(R.id.tvPatternText) @BindView(R.id.tvPatternText)
TextView tvPatternText; TextView tvPatternText;
@BindView(R.id.txtBadtry)
TextView txtBadtry;
/*
* Contains the bad tries
* */
private int tries = 0;
/*
* Seconds counter
* */
private int seconds = 15;
@ -111,10 +124,69 @@ public class PatternRequestActivity extends AppCompatActivity {
private void incorrect(){ private void incorrect(){
/*
* One more bad try
* */
++tries;
final Activity activity = this;
/*
* User can not go more up to 5 bad tries
* */
if(tries==4) {
tries = 0;
patternLockView.setEnabled(false);
txtBadtry.setVisibility(View.VISIBLE);
txtBadtry.setText(txtBadtry.getText().toString().replace("%%",String.valueOf(seconds)));
final Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
--seconds;
if(seconds==0){
t.cancel();
seconds = 15;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
patternLockView.setEnabled(true);
txtBadtry.setVisibility(View.INVISIBLE);
patternLockView.clearPattern();
patternLockView.requestFocus();
}
});
}
else{
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
txtBadtry.setText(activity.getResources().getString(R.string.wrong_pin_wait).replace("%%",String.valueOf(seconds)));
}
});
}
}
},
//Set how long before to start calling the TimerTask (in milliseconds)
1000,
//Set the amount of time between each execution (in milliseconds)
1000);
return;
}
/* /*
* Show error * Show error
* */ * */
final Activity activity = this;
tvPatternText.setText(activity.getResources().getString(R.string.Incorrect_pattern)); tvPatternText.setText(activity.getResources().getString(R.string.Incorrect_pattern));
tvPatternText.setTextColor(Color.RED); tvPatternText.setTextColor(Color.RED);
tvPatternText.setVisibility(View.VISIBLE); tvPatternText.setVisibility(View.VISIBLE);

View file

@ -18,11 +18,9 @@ public class InsightApiGenerator {
* Fecth all the transaciton for a giving address * Fecth all the transaciton for a giving address
* @param cryptoCoin the crypto net of the address * @param cryptoCoin the crypto net of the address
* @param address The address String * @param address The address String
* @param request the request api to response
* @param subscribe If needs to follow the address (Real time) * @param subscribe If needs to follow the address (Real time)
*/ */
public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, boolean subscribe){
ApiRequest request, boolean subscribe){
if(!transactionGetters.containsKey(cryptoCoin)){ if(!transactionGetters.containsKey(cryptoCoin)){
transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet()))); transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet())));
} }

View file

@ -31,6 +31,9 @@ public interface BitcoinAddressDao {
@Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'true' ") @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'true' ")
long getLastChangeAddress(long accountId); long getLastChangeAddress(long accountId);
@Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'false' ")
long getLastExternalAddress(long accountId);
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
public long[] insertBitcoinAddresses(BitcoinAddress... addresses); public long[] insertBitcoinAddresses(BitcoinAddress... addresses);
} }

View file

@ -28,6 +28,7 @@ import butterknife.OnTextChanged;
import cy.agorise.crystalwallet.R; import cy.agorise.crystalwallet.R;
import cy.agorise.crystalwallet.application.CrystalSecurityMonitor; import cy.agorise.crystalwallet.application.CrystalSecurityMonitor;
import cy.agorise.crystalwallet.models.GeneralSetting; import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.util.ChildViewPager;
import cy.agorise.crystalwallet.util.PasswordManager; import cy.agorise.crystalwallet.util.PasswordManager;
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
import cy.agorise.crystalwallet.viewmodels.validators.PinSecurityValidator; import cy.agorise.crystalwallet.viewmodels.validators.PinSecurityValidator;
@ -45,9 +46,17 @@ public class PatternSecurityFragment extends Fragment {
@BindView(R.id.tvPatternText) @BindView(R.id.tvPatternText)
TextView tvPatternText; TextView tvPatternText;
/*
* Contains the ChildViewPager to block the viewpager when the user is using the pattern control
* */
private ChildViewPager childViewPager;
private PatternLockViewListener actualPatternListener; private PatternLockViewListener actualPatternListener;
private String patternEntered; private String patternEntered;
public PatternSecurityFragment() { public PatternSecurityFragment() {
// Required empty public constructor // Required empty public constructor
} }
@ -80,6 +89,11 @@ public class PatternSecurityFragment extends Fragment {
return patternString; return patternString;
} }
public void setChildViewPager(ChildViewPager childViewPager) {
this.childViewPager = childViewPager;
}
public void removePatternListener(){ public void removePatternListener(){
if (actualPatternListener != null){ if (actualPatternListener != null){
patternLockView.removePatternLockListener(actualPatternListener); patternLockView.removePatternLockListener(actualPatternListener);
@ -96,7 +110,6 @@ public class PatternSecurityFragment extends Fragment {
actualPatternListener = new PatternLockViewListener() { actualPatternListener = new PatternLockViewListener() {
@Override @Override
public void onStarted() { public void onStarted() {
} }
@Override @Override
@ -193,8 +206,8 @@ public class PatternSecurityFragment extends Fragment {
* */ * */
tvPatternText.setText(getActivity().getResources().getString(R.string.Pattern_set_correctly)); tvPatternText.setText(getActivity().getResources().getString(R.string.Pattern_set_correctly));
tvPatternText.setTextColor(Color.GREEN); tvPatternText.setTextColor(Color.GREEN);
final Timer t = new Timer(); final Timer t_ = new Timer();
t.scheduleAtFixedRate(new TimerTask() { t_.scheduleAtFixedRate(new TimerTask() {
@Override @Override
public void run() { public void run() {
@ -203,7 +216,7 @@ public class PatternSecurityFragment extends Fragment {
@Override @Override
public void run() { public void run() {
t.cancel(); t_.cancel();
showNewPatternUI(); showNewPatternUI();
} }
}); });

View file

@ -83,6 +83,11 @@ public class SecuritySettingsFragment extends Fragment {
View v = inflater.inflate(R.layout.fragment_security_settings, container, false); View v = inflater.inflate(R.layout.fragment_security_settings, container, false);
ButterKnife.bind(this, v); ButterKnife.bind(this, v);
/*
* For now this will not be implemented
* */
sPocketSecurity.setEnabled(false);
securityPagerAdapter = new SecurityPagerAdapter(getChildFragmentManager()); securityPagerAdapter = new SecurityPagerAdapter(getChildFragmentManager());
mPager.setAdapter(securityPagerAdapter); mPager.setAdapter(securityPagerAdapter);
@ -96,7 +101,6 @@ public class SecuritySettingsFragment extends Fragment {
default: default:
mPager.setCurrentItem(0); mPager.setCurrentItem(0);
} }
mPager.setSwipeLocked(true);
TabLayout tabLayout = v.findViewById(R.id.tabs); TabLayout tabLayout = v.findViewById(R.id.tabs);
@ -134,7 +138,9 @@ public class SecuritySettingsFragment extends Fragment {
case 1: case 1:
return new PinSecurityFragment(); return new PinSecurityFragment();
case 2: case 2:
return new PatternSecurityFragment(); final PatternSecurityFragment patternSecurityFragment = new PatternSecurityFragment();
patternSecurityFragment.setChildViewPager(mPager);
return patternSecurityFragment;
} }
return null; //new OnConstructionFragment(); return null; //new OnConstructionFragment();

View file

@ -1,6 +1,5 @@
package cy.agorise.crystalwallet.manager; package cy.agorise.crystalwallet.manager;
import android.accounts.Account;
import android.content.Context; import android.content.Context;
import org.bitcoinj.core.Address; import org.bitcoinj.core.Address;
@ -26,7 +25,6 @@ import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout;
import cy.agorise.crystalwallet.application.CrystalApplication;
import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.CryptoCoin; import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.models.AccountSeed; import cy.agorise.crystalwallet.models.AccountSeed;
@ -37,11 +35,11 @@ import cy.agorise.crystalwallet.models.CryptoCoinBalance;
import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoCurrency;
import cy.agorise.crystalwallet.models.CryptoNetAccount; import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.models.GTxIO; import cy.agorise.crystalwallet.requestmanagers.BitcoinSendRequest;
import cy.agorise.crystalwallet.models.GeneralCoinAddress; import cy.agorise.crystalwallet.requestmanagers.CreateBitcoinAccountRequest;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestsListener; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestsListener;
import cy.agorise.crystalwallet.requestmanagers.GeneralAccountSendRequest; import cy.agorise.crystalwallet.requestmanagers.NextBitcoinAccountAddressRequest;
import cy.agorise.graphenej.Util; import cy.agorise.graphenej.Util;
public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
@ -85,9 +83,14 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
@Override @Override
public void onNewRequest(CryptoNetInfoRequest request) { public void onNewRequest(CryptoNetInfoRequest request) {
if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ //if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){
if(request instanceof GeneralAccountSendRequest){ if(request.getCoin().equals(this.cryptoCoin)){
this.send((GeneralAccountSendRequest)request); if(request instanceof BitcoinSendRequest) {
this.send((BitcoinSendRequest) request);
}else if(request instanceof CreateBitcoinAccountRequest){
}else if(request instanceof NextBitcoinAccountAddressRequest){
this.getNextAddress((NextBitcoinAccountAddressRequest) request);
}else{ }else{
System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request "); System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request ");
} }
@ -255,7 +258,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance); db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance);
} }
public void send(final GeneralAccountSendRequest request){ public void send(final BitcoinSendRequest request){
//TODO check server connection //TODO check server connection
//TODO validate to address //TODO validate to address
@ -271,19 +274,19 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext());
db.bitcoinTransactionDao(); db.bitcoinTransactionDao();
List<BitcoinTransactionGTxIO> utxos = getUtxos(request.getAccount().getId(),db); List<BitcoinTransactionGTxIO> utxos = getUtxos(request.getSourceAccount().getId(),db);
if(currentAmount< request.getAmount() + fee){ if(currentAmount< request.getAmount() + fee){
request.setStatus(GeneralAccountSendRequest.StatusCode.NO_BALANCE); request.setStatus(BitcoinSendRequest.StatusCode.NO_BALANCE);
return; return;
} }
AccountSeed seed = db.accountSeedDao().findById(request.getAccount().getSeedId()); AccountSeed seed = db.accountSeedDao().findById(request.getSourceAccount().getSeedId());
DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(),
new ChildNumber(44, true)); new ChildNumber(44, true));
DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey,
new ChildNumber(cryptoCoin.getCoinNumber(), true)); new ChildNumber(cryptoCoin.getCoinNumber(), true));
DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey,
new ChildNumber(request.getAccount().getAccountIndex(), true)); new ChildNumber(request.getSourceAccount().getAccountIndex(), true));
DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey,
new ChildNumber(0, false)); new ChildNumber(0, false));
DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey,
@ -309,7 +312,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
//Change address //Change address
long remain = currentAmount - request.getAmount() - fee; long remain = currentAmount - request.getAmount() - fee;
if( remain > 0 ) { if( remain > 0 ) {
long index = db.bitcoinAddressDao().getLastChangeAddress(request.getAccount().getId()); long index = db.bitcoinAddressDao().getLastChangeAddress(request.getSourceAccount().getId());
BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index); BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index);
Address changeAddr; Address changeAddr;
if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){ if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){
@ -323,7 +326,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
} }
btAddress = new BitcoinAddress(); btAddress = new BitcoinAddress();
btAddress.setIndex(index); btAddress.setIndex(index);
btAddress.setAccountId(request.getAccount().getId()); btAddress.setAccountId(request.getSourceAccount().getId());
btAddress.setChange(true); btAddress.setChange(true);
btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString()); btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString());
db.bitcoinAddressDao().insertBitcoinAddresses(btAddress); db.bitcoinAddressDao().insertBitcoinAddresses(btAddress);
@ -342,7 +345,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
if(btAddress.isChange()){ if(btAddress.isChange()){
addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)); addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false));
}else{ }else{
addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), true)); addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) btAddress.getIndex(), true));
} }
tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true); tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true);
} }
@ -350,24 +353,51 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
InsightApiGenerator.broadcastTransaction(cryptoCoin,Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() { InsightApiGenerator.broadcastTransaction(cryptoCoin,Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() {
@Override @Override
public void success(Object answer, int idPetition) { public void success(Object answer, int idPetition) {
request.setStatus(GeneralAccountSendRequest.StatusCode.SUCCEEDED); request.setStatus(BitcoinSendRequest.StatusCode.SUCCEEDED);
} }
@Override @Override
public void fail(int idPetition) { public void fail(int idPetition) {
request.setStatus(GeneralAccountSendRequest.StatusCode.PETITION_FAILED); request.setStatus(BitcoinSendRequest.StatusCode.PETITION_FAILED);
} }
})); }));
} }
@Override @Override
public void fail(int idPetition) { public void fail(int idPetition) {
request.setStatus(GeneralAccountSendRequest.StatusCode.NO_FEE); request.setStatus(BitcoinSendRequest.StatusCode.NO_FEE);
} }
})); }));
} }
private void getNextAddress(NextBitcoinAccountAddressRequest request){
CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext());
long index = db.bitcoinAddressDao().getLastExternalAddress(request.getAccount().getId());
index++;
AccountSeed seed = db.accountSeedDao().findById(request.getAccount().getSeedId());
DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(),
new ChildNumber(44, true));
DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey,
new ChildNumber(cryptoCoin.getCoinNumber(), true));
DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey,
new ChildNumber(request.getAccount().getAccountIndex(), true));
DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey,
new ChildNumber(0, false));
ECKey addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) index, true));
BitcoinAddress address = new BitcoinAddress();
address.setChange(false);
address.setAccountId(request.getAccount().getId());
address.setIndex(index);
String addressString =addrKey.toAddress(this.cryptoCoin.getParameters()).toString();
address.setAddress(addressString);
db.bitcoinAddressDao().insertBitcoinAddresses(address);
InsightApiGenerator.getTransactionFromAddress(this.cryptoCoin,addressString,true);
request.setAddress(addressString);
request.setStatus(NextBitcoinAccountAddressRequest.StatusCode.SUCCEEDED);
}
private List<BitcoinTransactionGTxIO> getUtxos(long accountId, CrystalDatabase db){ private List<BitcoinTransactionGTxIO> getUtxos(long accountId, CrystalDatabase db){
List<BitcoinTransactionGTxIO> answer = new ArrayList<>(); List<BitcoinTransactionGTxIO> answer = new ArrayList<>();
List<BitcoinTransactionGTxIO> bTGTxI = new ArrayList<>(); List<BitcoinTransactionGTxIO> bTGTxI = new ArrayList<>();

View file

@ -21,6 +21,8 @@ public class BitcoinSendRequest extends CryptoNetInfoRequest {
SUCCEEDED, SUCCEEDED,
NO_INTERNET, NO_INTERNET,
NO_SERVER_CONNECTION, NO_SERVER_CONNECTION,
NO_BALANCE,
NO_FEE,
PETITION_FAILED PETITION_FAILED
} }

View file

@ -1,85 +0,0 @@
package cy.agorise.crystalwallet.requestmanagers;
import android.content.Context;
import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.models.CryptoNetAccount;
public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
/**
* The status code of this request
*/
public enum StatusCode{
NOT_STARTED,
SUCCEEDED,
NO_INTERNET,
NO_SERVER_CONNECTION,
BAD_TO_ADDRESS,
NO_FEE,
NO_BALANCE,
PETITION_FAILED
}
// The app context
private Context mContext;
//The soruce Account
private CryptoNetAccount mAccount;
// The destination account address
private String mToAccount;
// The amount of the transaction
private long mAmount;
// The memo, can be null
private String mMemo;
// The state of this request
private StatusCode status = StatusCode.NOT_STARTED;
public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount, String memo) {
super(coin);
this.mContext = context;
this.mAccount = account;
this.mToAccount = toAccount;
this.mAmount = amount;
this.mMemo = memo;
}
public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount) {
this(coin,context,account,toAccount,amount,null);
}
public Context getContext() {
return mContext;
}
public CryptoNetAccount getAccount() {
return mAccount;
}
public String getToAccount() {
return mToAccount;
}
public long getAmount() {
return mAmount;
}
public String getMemo() {
return mMemo;
}
public void validate(){
if ((this.status != StatusCode.NOT_STARTED)){
this._fireOnCarryOutEvent();
}
}
public void setStatus(StatusCode code){
this.status = code;
this._fireOnCarryOutEvent();
}
public StatusCode getStatus() {
return status;
}
}

View file

@ -19,6 +19,8 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest {
private CryptoCoin cryptoCoin; private CryptoCoin cryptoCoin;
private Context context; private Context context;
private String address = null;
/** /**
* The status code of this request * The status code of this request
*/ */
@ -62,4 +64,12 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest {
public StatusCode getStatus() { public StatusCode getStatus() {
return status; return status;
} }
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
} }

View file

@ -4,6 +4,10 @@ import android.content.Context;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
import java.lang.reflect.Field;
/** /**
* Created by xd on 1/18/18. * Created by xd on 1/18/18.
@ -14,36 +18,47 @@ import android.view.MotionEvent;
public class ChildViewPager extends ViewPager { public class ChildViewPager extends ViewPager {
private boolean swipeLocked;
public ChildViewPager(Context context) { public ChildViewPager(Context context) {
super(context); super(context);
setMyScroller();
} }
public ChildViewPager(Context context, AttributeSet attrs) { public ChildViewPager(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public boolean getSwipeLocked() {
return swipeLocked;
}
public void setSwipeLocked(boolean swipeLocked) {
this.swipeLocked = swipeLocked;
}
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
return !swipeLocked && super.onTouchEvent(event); // stop swipe
return false;
} }
@Override @Override
public boolean onInterceptTouchEvent(MotionEvent event) { public boolean onInterceptTouchEvent(MotionEvent event) {
return !swipeLocked && super.onInterceptTouchEvent(event); // stop switching pages
return false;
}
private void setMyScroller() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new MyScroller(getContext()));
} catch (Exception e) {
e.printStackTrace();
}
}
public class MyScroller extends Scroller {
public MyScroller(Context context) {
super(context, new DecelerateInterpolator());
} }
@Override @Override
public boolean canScrollHorizontally(int direction) { public void startScroll(int startX, int startY, int dx, int dy, int duration) {
return !swipeLocked && super.canScrollHorizontally(direction); super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
}
} }
} }

View file

@ -101,6 +101,7 @@ class BitsharesAccountNameValidation : CustomValidationField, UIValidator {
result = false result = false
accountNameField.fieldValidatorModel.setInvalid() accountNameField.fieldValidatorModel.setInvalid()
accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_at_least_one_character) accountNameField.fieldValidatorModel.message = this.accountNameField.resources.getString(R.string.create_account_window_err_at_least_one_character)
} else { } else {
/* /*

View file

@ -21,4 +21,15 @@
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:background="@drawable/gradient"/> android:background="@drawable/gradient"/>
<TextView
android:id="@+id/txtBadtry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/patternLockView"
android:text="@string/wrong_pin_wait"
android:layout_marginTop="5dp"
android:layout_centerHorizontal="true"
android:textColor="@color/red"
android:visibility="invisible"/>
</RelativeLayout> </RelativeLayout>

View file

@ -91,6 +91,12 @@
<string name="save">SAVE</string> <string name="save">SAVE</string>
<string name="next">NEXT</string> <string name="next">NEXT</string>
<string name="ERROR_UNRECOGNIZABLE">An error ocurred attempting to import the account</string>
<string name="NO_ACCOUNT_DATA">The account does not have any data</string>
<string name="BAD_SEED">The seed is not valid</string>
<string name="ACCOUNT_DOESNT_EXIST">The account does not exists</string>
<string name="NO_SERVER_CONNECTION">There was an error with the connection. Try again later</string>
<string name="ASK_PERMISSION">A permission need to be granted before to continue</string> <string name="ASK_PERMISSION">A permission need to be granted before to continue</string>
<string name="please_enter_brainkey">Please enter brainkey</string> <string name="please_enter_brainkey">Please enter brainkey</string>
@ -214,7 +220,7 @@
<string name="fee_capital">Fee</string> <string name="fee_capital">Fee</string>
<string name="ok">OK</string> <string name="ok">OK</string>
<string name="wrong_pin_wait">Wrong PIN you have to wait %% seconds ...</string> <string name="wrong_pin_wait">Wrong match you have to wait %% seconds ...</string>
<string name="loading">Loading...</string> <string name="loading">Loading...</string>
<string name="pay_to">Pay to</string> <string name="pay_to">Pay to</string>