- Pattern Lock Setting added

This commit is contained in:
Javier Varona 2018-05-08 22:07:12 -04:00
parent 2f37534bc2
commit 6598d4aacb
13 changed files with 401 additions and 13 deletions

View file

@ -68,4 +68,5 @@ dependencies {
implementation 'com.github.esafirm.android-image-picker:imagepicker:1.11.1' implementation 'com.github.esafirm.android-image-picker:imagepicker:1.11.1'
compile 'id.zelory:compressor:2.1.0' compile 'id.zelory:compressor:2.1.0'
compile 'com.vincent.filepicker:MultiTypeFilePicker:1.0.7' compile 'com.vincent.filepicker:MultiTypeFilePicker:1.0.7'
compile 'com.andrognito.patternlockview:patternlockview:1.0.0'
} }

View file

@ -47,6 +47,9 @@
<activity android:name=".activities.PinRequestActivity" <activity android:name=".activities.PinRequestActivity"
android:noHistory="true"> android:noHistory="true">
</activity> </activity>
<activity android:name=".activities.PatternRequestActivity"
android:noHistory="true">
</activity>
<activity <activity
android:name=".activities.SettingsActivity" android:name=".activities.SettingsActivity"
android:theme="@style/AppTheme.NoActionBar" android:theme="@style/AppTheme.NoActionBar"

View file

@ -0,0 +1,103 @@
package cy.agorise.crystalwallet.activities;
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.v7.app.AppCompatActivity;
import android.text.Editable;
import android.widget.EditText;
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;
public class PatternRequestActivity extends AppCompatActivity {
private String patternEncrypted;
@Override
public void onBackPressed() {
//Do nothing to prevent the user to use the back button
}
@BindView(R.id.patternLockView)
PatternLockView patternLockView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pattern_request);
ButterKnife.bind(this);
GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(this).get(GeneralSettingListViewModel.class);
LiveData<List<GeneralSetting>> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
final PatternRequestActivity thisActivity = this;
generalSettingsLiveData.observe(this, new Observer<List<GeneralSetting>>() {
@Override
public void onChanged(@Nullable List<GeneralSetting> 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<PatternLockView.Dot> progressPattern) {
}
@Override
public void onComplete(List<PatternLockView.Dot> pattern) {
if (PasswordManager.checkPassword(patternEncrypted,patternToString(pattern))){
thisActivity.finish();
} else {
patternLockView.clearPattern();
patternLockView.requestFocus();
}
}
@Override
public void onCleared() {
}
});
}
break;
}
}
}
}
});
}
public String patternToString(List<PatternLockView.Dot> pattern){
String patternString = "";
for (PatternLockView.Dot nextDot : pattern){
patternString = patternString+(nextDot.getRow()*3+nextDot.getColumn());
}
return patternString;
}
}

View file

@ -100,8 +100,8 @@ public class SettingsActivity extends AppCompatActivity{
return new SecuritySettingsFragment(); return new SecuritySettingsFragment();
case 2: case 2:
return new BackupsSettingsFragment(); return new BackupsSettingsFragment();
case 3: //case 3:
return new AccountsSettingsFragment(); // return new AccountsSettingsFragment();
} }
@ -110,7 +110,7 @@ public class SettingsActivity extends AppCompatActivity{
@Override @Override
public int getCount() { public int getCount() {
return 4; return 3;
} }
} }

View file

@ -13,6 +13,7 @@ import android.support.v4.app.FragmentActivity;
import java.util.List; import java.util.List;
import cy.agorise.crystalwallet.activities.PatternRequestActivity;
import cy.agorise.crystalwallet.activities.PinRequestActivity; import cy.agorise.crystalwallet.activities.PinRequestActivity;
import cy.agorise.crystalwallet.models.GeneralSetting; import cy.agorise.crystalwallet.models.GeneralSetting;
import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel; import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
@ -24,6 +25,7 @@ import cy.agorise.crystalwallet.viewmodels.GeneralSettingListViewModel;
public class CrystalSecurityMonitor implements Application.ActivityLifecycleCallbacks { public class CrystalSecurityMonitor implements Application.ActivityLifecycleCallbacks {
private int numStarted = 0; private int numStarted = 0;
private String passwordEncrypted; private String passwordEncrypted;
private String patternEncrypted;
public CrystalSecurityMonitor(final FragmentActivity fragmentActivity){ public CrystalSecurityMonitor(final FragmentActivity fragmentActivity){
GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(fragmentActivity).get(GeneralSettingListViewModel.class); GeneralSettingListViewModel generalSettingListViewModel = ViewModelProviders.of(fragmentActivity).get(GeneralSettingListViewModel.class);
@ -38,12 +40,17 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
if (generalSettings != null){ if (generalSettings != null){
for (GeneralSetting generalSetting:generalSettings) { for (GeneralSetting generalSetting:generalSettings) {
if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){ if (generalSetting.getName().equals(GeneralSetting.SETTING_PASSWORD)){
founded = true;
if (!generalSetting.getValue().isEmpty()){ if (!generalSetting.getValue().isEmpty()){
passwordEncrypted = generalSetting.getValue(); passwordEncrypted = generalSetting.getValue();
callPasswordRequest(fragmentActivity); callPasswordRequest(fragmentActivity);
} }
break; 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 @Override
public void onActivityStarted(Activity activity) { public void onActivityStarted(Activity activity) {
if (numStarted == 0) { 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); callPasswordRequest(activity);
} }
} }
@ -65,7 +75,10 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
public void onActivityStopped(Activity activity) { public void onActivityStopped(Activity activity) {
numStarted--; numStarted--;
if (numStarted == 0) { 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); callPasswordRequest(activity);
} }
} }
@ -73,9 +86,16 @@ public class CrystalSecurityMonitor implements Application.ActivityLifecycleCall
public void callPasswordRequest(Activity activity){ public void callPasswordRequest(Activity activity){
if ((!activity.getIntent().hasExtra("ACTIVITY_TYPE")) || (!activity.getIntent().getStringExtra("ACTIVITY_TYPE").equals("PASSWORD_REQUEST"))) { if ((!activity.getIntent().hasExtra("ACTIVITY_TYPE")) || (!activity.getIntent().getStringExtra("ACTIVITY_TYPE").equals("PASSWORD_REQUEST"))) {
Intent intent = new Intent(activity, PinRequestActivity.class); Intent intent = null;
intent.putExtra("ACTIVITY_TYPE", "PASSWORD_REQUEST"); if ((this.passwordEncrypted != null) && (!this.passwordEncrypted.equals(""))) {
activity.startActivity(intent); 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);
}
} }
} }

View file

@ -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<List<GeneralSetting>> generalSettingsLiveData = generalSettingListViewModel.getGeneralSettingList();
generalSettingsLiveData.observe(this, new Observer<List<GeneralSetting>>() {
@Override
public void onChanged(@Nullable List<GeneralSetting> 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<PatternLockView.Dot> 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<PatternLockView.Dot> progressPattern) {
}
@Override
public void onComplete(List<PatternLockView.Dot> 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<PatternLockView.Dot> progressPattern) {
}
@Override
public void onComplete(List<PatternLockView.Dot> 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<PatternLockView.Dot> progressPattern) {
}
@Override
public void onComplete(List<PatternLockView.Dot> pattern) {
if (PasswordManager.checkPassword(patternGeneralSetting.getValue(),patternToString(pattern))){
showNewPatternUI();
}
}
@Override
public void onCleared() {
}
};
patternLockView.addPatternLockListener(actualPatternListener);
}
}

View file

@ -69,7 +69,7 @@ public class SecuritySettingsFragment extends Fragment {
case 1: case 1:
return new PinSecurityFragment(); return new PinSecurityFragment();
case 2: case 2:
return new BackupsSettingsFragment(); return new PatternSecurityFragment();
} }
return null; //new OnConstructionFragment(); return null; //new OnConstructionFragment();

View file

@ -20,6 +20,7 @@ public class GeneralSetting {
public final static String SETTING_NAME_PREFERRED_LANGUAGE = "PREFERRED_LANGUAGE"; 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_NAME_TIME_ZONE = "TIME_ZONE";
public final static String SETTING_PASSWORD = "PASSWORD"; 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"; public final static String SETTING_NAME_RECEIVED_FUNDS_SOUND_PATH = "RECEIVED_FUNDS_SOUND_PATH";
/** /**

View file

@ -31,7 +31,7 @@ public class GeneralSettingListViewModel extends AndroidViewModel {
} }
public void saveGeneralSetting(GeneralSetting generalSetting){ public void saveGeneralSetting(GeneralSetting generalSetting){
this.db.generalSettingDao().insertGeneralSetting(generalSetting); this.db.generalSettingDao ().insertGeneralSetting(generalSetting);
} }
public void saveGeneralSettings(GeneralSetting... generalSettings){ public void saveGeneralSettings(GeneralSetting... generalSettings){

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:background="@color/colorPrimary">
<com.andrognito.patternlockview.PatternLockView
android:id="@+id/patternLockView"
android:layout_width="280dp"
android:layout_height="280dp" />
</LinearLayout>
</LinearLayout>

View file

@ -104,11 +104,12 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/backups" /> android:text="@string/backups" />
<android.support.design.widget.TabItem <!--<android.support.design.widget.TabItem
android:id="@+id/tabItem4" android:id="@+id/tabItem4"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/accounts" /> android:text="@string/accounts"
android:visibility="gone" />-->
</android.support.design.widget.TabLayout> </android.support.design.widget.TabLayout>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvPatternText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.andrognito.patternlockview.PatternLockView
android:id="@+id/patternLockView"
android:layout_width="280dp"
android:layout_height="280dp"/>
</android.support.constraint.ConstraintLayout>

View file

@ -68,6 +68,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="140dp" android:layout_height="140dp"
android:background="@color/lightGray" android:background="@color/lightGray"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />