diff --git a/app/build.gradle b/app/build.gradle
index a80aac7..812d19b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -68,4 +68,5 @@ dependencies {
implementation 'com.github.esafirm.android-image-picker:imagepicker:1.11.1'
compile 'id.zelory:compressor:2.1.0'
compile 'com.vincent.filepicker:MultiTypeFilePicker:1.0.7'
+ compile 'com.andrognito.patternlockview:patternlockview:1.0.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3b5bc5e..2a633fc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -47,6 +47,9 @@
+
+
> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
+
+ final PatternRequestActivity thisActivity = this;
+
+ generalSettingsLiveData.observe(this, new Observer>() {
+ @Override
+ public void onChanged(@Nullable List generalSettings) {
+ patternEncrypted = "";
+
+ if (generalSettings != null){
+ for (GeneralSetting generalSetting:generalSettings) {
+ if (generalSetting.getName().equals(GeneralSetting.SETTING_PATTERN)){
+ if (!generalSetting.getValue().isEmpty()){
+ patternEncrypted = generalSetting.getValue();
+
+ patternLockView.addPatternLockListener(new PatternLockViewListener() {
+ @Override
+ public void onStarted() {
+
+ }
+
+ @Override
+ public void onProgress(List progressPattern) {
+
+ }
+
+ @Override
+ public void onComplete(List pattern) {
+ if (PasswordManager.checkPassword(patternEncrypted,patternToString(pattern))){
+ thisActivity.finish();
+ } else {
+ patternLockView.clearPattern();
+ patternLockView.requestFocus();
+ }
+ }
+
+ @Override
+ public void onCleared() {
+
+ }
+ });
+ }
+ break;
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public String patternToString(List pattern){
+ String patternString = "";
+ for (PatternLockView.Dot nextDot : pattern){
+ patternString = patternString+(nextDot.getRow()*3+nextDot.getColumn());
+ }
+
+ return patternString;
+ }
+}
+
+
diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java
index 222c74a..8f708f9 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/activities/SettingsActivity.java
@@ -100,8 +100,8 @@ public class SettingsActivity extends AppCompatActivity{
return new SecuritySettingsFragment();
case 2:
return new BackupsSettingsFragment();
- case 3:
- return new AccountsSettingsFragment();
+ //case 3:
+ // return new AccountsSettingsFragment();
}
@@ -110,7 +110,7 @@ public class SettingsActivity extends AppCompatActivity{
@Override
public int getCount() {
- return 4;
+ return 3;
}
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java
index 852daa9..b08726c 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalSecurityMonitor.java
@@ -13,6 +13,7 @@ import android.support.v4.app.FragmentActivity;
import java.util.List;
+import cy.agorise.crystalwallet.activities.PatternRequestActivity;
import cy.agorise.crystalwallet.activities.PinRequestActivity;
import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
@@ -24,6 +25,7 @@ import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
public class CrystalSecurityMonitor implements Application.ActivityLifecycleCallbacks {
private int numStarted = 0;
private String passwordEncrypted;
+ private String patternEncrypted;
public CrystalSecurityMonitor(final FragmentActivity fragmentActivity){
GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(fragmentActivity).get(GeneralSettingListViewModel.class);
@@ -38,12 +40,17 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
if (generalSettings != null){
for (GeneralSetting generalSetting:generalSettings) {
if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){
- founded = true;
if (!generalSetting.getValue().isEmpty()){
passwordEncrypted = generalSetting.getValue();
callPasswordRequest(fragmentActivity);
}
break;
+ } else if (generalSetting.getName().equals(GeneralSetting.SETTING_PATTERN)){
+ if (!generalSetting.getValue().isEmpty()){
+ patternEncrypted = generalSetting.getValue();
+ callPasswordRequest(fragmentActivity);
+ }
+ break;
}
}
}
@@ -54,7 +61,10 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
@Override
public void onActivityStarted(Activity activity) {
if (numStarted == 0) {
- if ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals(""))) {
+ if (
+ ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals("")))
+ || ((this.patternEncrypted != null) && (!this.patternEncrypted.equals("")))
+ ) {
callPasswordRequest(activity);
}
}
@@ -65,7 +75,10 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
public void onActivityStopped(Activity activity) {
numStarted--;
if (numStarted == 0) {
- if ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals(""))) {
+ if (
+ ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals("")))
+ || ((this.patternEncrypted != null) && (!this.patternEncrypted.equals("")))
+ ) {
callPasswordRequest(activity);
}
}
@@ -73,9 +86,16 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
public void callPasswordRequest(Activity activity){
if ((!activity.getIntent().hasExtra("ACTIVITY_TYPE")) || (!activity.getIntent().getStringExtra("ACTIVITY_TYPE").equals("PASSWORD_REQUEST"))) {
- Intent intent = new Intent(activity, PinRequestActivity.class);
- intent.putExtra("ACTIVITY_TYPE", "PASSWORD_REQUEST");
- activity.startActivity(intent);
+ Intent intent = null;
+ if ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals(""))) {
+ intent = new Intent(activity, PinRequestActivity.class);
+ } else if ((this.patternEncrypted != null) && (!this.patternEncrypted.equals(""))) {
+ intent = new Intent(activity, PatternRequestActivity.class);
+ }
+ if (intent != null) {
+ intent.putExtra("ACTIVITY_TYPE", "PASSWORD_REQUEST");
+ activity.startActivity(intent);
+ }
}
}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java
new file mode 100644
index 0000000..2a53dd7
--- /dev/null
+++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/PatternSecurityFragment.java
@@ -0,0 +1,223 @@
+package cy.agorise.crystalwallet.fragments;
+
+import android.arch.lifecycle.LiveData;
+import android.arch.lifecycle.Observer;
+import android.arch.lifecycle.ViewModelProviders;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.andrognito.patternlockview.PatternLockView;
+import com.andrognito.patternlockview.listener.PatternLockViewListener;
+
+import java.util.List;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnTextChanged;
+import cy.agorise.crystalwallet.R;
+import cy.agorise.crystalwallet.models.GeneralSetting;
+import cy.agorise.crystalwallet.util.PasswordManager;
+import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
+import cy.agorise.crystalwallet.viewmodels.validators.PinSecurityValidator;
+import cy.agorise.crystalwallet.viewmodels.validators.UIValidatorListener;
+import cy.agorise.crystalwallet.viewmodels.validators.validationfields.ValidationField;
+
+/**
+ * Created by xd on 1/18/18.
+ */
+
+public class PatternSecurityFragment extends Fragment {
+
+ GeneralSettingListViewModel generalSettingListViewModel;
+ GeneralSetting patternGeneralSetting;
+ //PatternSecurityValidator patternSecurityValidator;
+
+ @BindView(R.id.patternLockView)
+ PatternLockView patternLockView;
+ @BindView(R.id.tvPatternText)
+ TextView tvPatternText;
+
+ private PatternLockViewListener actualPatternListener;
+ private String patternEntered;
+
+ public PatternSecurityFragment() {
+ // Required empty public constructor
+ }
+
+ public static PatternSecurityFragment newInstance() {
+ PatternSecurityFragment fragment = new PatternSecurityFragment();
+ Bundle args = new Bundle();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View v = inflater.inflate(R.layout.fragment_pattern_security, container, false);
+ ButterKnife.bind(this, v);
+
+ generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class);
+ LiveData> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
+
+ generalSettingsLiveData.observe(this, new Observer>() {
+ @Override
+ public void onChanged(@Nullable List generalSettings) {
+ boolean founded = false;
+
+ if (generalSettings != null){
+ for (GeneralSetting generalSetting:generalSettings) {
+ if (generalSetting.getName().equals(GeneralSetting.SETTING_PATTERN)){
+ founded = true;
+ if (!generalSetting.getValue().isEmpty()){
+ patternGeneralSetting = generalSetting;
+ showEnterPatternUI();
+ } else {
+ showNewPatternUI();
+ }
+ break;
+ }
+ }
+ if (!founded){
+ showNewPatternUI();
+ }
+ } else {
+ showNewPatternUI();
+ }
+ }
+ });
+
+ return v;
+ }
+
+ public String patternToString(List pattern){
+ String patternString = "";
+ for (PatternLockView.Dot nextDot : pattern){
+ patternString = patternString+(nextDot.getRow()*3+nextDot.getColumn());
+ }
+
+ return patternString;
+ }
+
+ public void removePatternListener(){
+ if (actualPatternListener != null){
+ patternLockView.removePatternLockListener(actualPatternListener);
+ actualPatternListener = null;
+ }
+ }
+
+ public void showNewPatternUI(){
+ removePatternListener();
+ patternLockView.clearPattern();
+ tvPatternText.setText("Enter new pattern");
+
+ actualPatternListener = new PatternLockViewListener() {
+ @Override
+ public void onStarted() {
+
+ }
+
+ @Override
+ public void onProgress(List progressPattern) {
+
+ }
+
+ @Override
+ public void onComplete(List pattern) {
+ patternEntered = patternToString(pattern);
+ showConfirmPatternUI();
+ }
+
+ @Override
+ public void onCleared() {
+
+ }
+ };
+ patternLockView.addPatternLockListener(actualPatternListener);
+ }
+
+ public void showConfirmPatternUI(){
+ removePatternListener();
+ patternLockView.clearPattern();
+ patternLockView.requestFocus();
+ tvPatternText.setText("Confirm new pattern");
+
+ actualPatternListener = new PatternLockViewListener() {
+ @Override
+ public void onStarted() {
+
+ }
+
+ @Override
+ public void onProgress(List progressPattern) {
+
+ }
+
+ @Override
+ public void onComplete(List pattern) {
+ if (patternEntered.equals(patternToString(pattern))){
+ savePattern(patternEntered);
+ showEnterPatternUI();
+ }
+ }
+
+ @Override
+ public void onCleared() {
+
+ }
+ };
+ patternLockView.addPatternLockListener(actualPatternListener);
+ }
+
+ public void savePattern(String pattern){
+ String patternEncripted = PasswordManager.encriptPassword(pattern);
+
+ if (patternGeneralSetting == null) {
+ patternGeneralSetting = new GeneralSetting();
+ patternGeneralSetting.setName(GeneralSetting.SETTING_PATTERN);
+ }
+
+ patternGeneralSetting.setValue(patternEncripted);
+ generalSettingListViewModel.saveGeneralSetting(patternGeneralSetting);
+ }
+
+ public void showEnterPatternUI(){
+ removePatternListener();
+ patternLockView.clearPattern();
+ tvPatternText.setText("Enter old pattern");
+
+ actualPatternListener = new PatternLockViewListener() {
+ @Override
+ public void onStarted() {
+
+ }
+
+ @Override
+ public void onProgress(List progressPattern) {
+
+ }
+
+ @Override
+ public void onComplete(List pattern) {
+ if (PasswordManager.checkPassword(patternGeneralSetting.getValue(),patternToString(pattern))){
+ showNewPatternUI();
+ }
+ }
+
+ @Override
+ public void onCleared() {
+
+ }
+ };
+ patternLockView.addPatternLockListener(actualPatternListener);
+ }
+}
diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java
index 0407bcf..39e4a25 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SecuritySettingsFragment.java
@@ -69,7 +69,7 @@ public class SecuritySettingsFragment extends Fragment {
case 1:
return new PinSecurityFragment();
case 2:
- return new BackupsSettingsFragment();
+ return new PatternSecurityFragment();
}
return null; //new OnConstructionFragment();
diff --git a/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java b/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java
index 62bab19..80edd47 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/models/GeneralSetting.java
@@ -20,6 +20,7 @@ public class GeneralSetting {
public final static String SETTING_NAME_PREFERRED_LANGUAGE = "PREFERRED_LANGUAGE";
public final static String SETTING_NAME_TIME_ZONE = "TIME_ZONE";
public final static String SETTING_PASSWORD = "PASSWORD";
+ public final static String SETTING_PATTERN = "PATTERN";
public final static String SETTING_NAME_RECEIVED_FUNDS_SOUND_PATH = "RECEIVED_FUNDS_SOUND_PATH";
/**
diff --git a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/GeneralSettingListViewModel.java b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/GeneralSettingListViewModel.java
index 22b2feb..b3d3c35 100644
--- a/app/src/main/java/cy/agorise/crystalwallet/viewmodels/GeneralSettingListViewModel.java
+++ b/app/src/main/java/cy/agorise/crystalwallet/viewmodels/GeneralSettingListViewModel.java
@@ -31,7 +31,7 @@ public class GeneralSettingListViewModel extends AndroidViewModel {
}
public void saveGeneralSetting(GeneralSetting generalSetting){
- this.db.generalSettingDao().insertGeneralSetting(generalSetting);
+ this.db.generalSettingDao ().insertGeneralSetting(generalSetting);
}
public void saveGeneralSettings(GeneralSetting... generalSettings){
diff --git a/app/src/main/res/layout/activity_pattern_request.xml b/app/src/main/res/layout/activity_pattern_request.xml
new file mode 100644
index 0000000..9eedb0f
--- /dev/null
+++ b/app/src/main/res/layout/activity_pattern_request.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index 2e76881..7b91bba 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -104,11 +104,12 @@
android:layout_height="wrap_content"
android:text="@string/backups" />
-
+ android:text="@string/accounts"
+ android:visibility="gone" />-->
diff --git a/app/src/main/res/layout/fragment_pattern_security.xml b/app/src/main/res/layout/fragment_pattern_security.xml
new file mode 100644
index 0000000..643a48f
--- /dev/null
+++ b/app/src/main/res/layout/fragment_pattern_security.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_security_settings.xml b/app/src/main/res/layout/fragment_security_settings.xml
index 19840d0..d3ae66f 100644
--- a/app/src/main/res/layout/fragment_security_settings.xml
+++ b/app/src/main/res/layout/fragment_security_settings.xml
@@ -68,6 +68,7 @@
android:layout_width="match_parent"
android:layout_height="140dp"
android:background="@color/lightGray"
+ android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />