Several fixs and UI update

Fix fingerprint cancel button crash
Update fingerprint dialog
This commit is contained in:
Tanguy Herbron 2018-03-02 12:19:57 +01:00
parent 55819c422e
commit b7c2e57824
7 changed files with 251 additions and 175 deletions

View File

@ -21,6 +21,7 @@ import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.RingtonePreference;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
@ -65,14 +66,6 @@ import javax.crypto.SecretKey;
*/
public class SettingsActivity extends AppCompatPreferenceActivity {
private static final String KEY_NAME = "NAUKEY";
private Cipher cipher;
private KeyStore keyStore;
private KeyGenerator keyGenerator;
private FingerprintManager.CryptoObject cryptoObject;
private FingerprintManager fingerprintManager;
private KeyguardManager keyguardManager;
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
@ -140,6 +133,9 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
finish();
return true;
}
Log.d("coinfolio", "hello");
return super.onOptionsItemSelected(item);
}
@ -169,120 +165,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
super.onCreate(savedInstanceState);
setupActionBar();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
if(preferences.getBoolean("enable_fingerprint", false))
{
FingerprintDialogFragment newFragment = FingerprintDialogFragment.newInstance();
newFragment.setCancelable(false);
newFragment.show(getFragmentManager(), "dialog");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
if(!fingerprintManager.isHardwareDetected())
{
findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED)
{
findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
if(!fingerprintManager.hasEnrolledFingerprints())
{
findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
if(!keyguardManager.isKeyguardSecure())
{
findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
else
{
try {
generateKey();
} catch (FingerprintException e) {
e.printStackTrace();
}
if(initCipher())
{
cryptoObject = new FingerprintManager.CryptoObject(cipher);
FingerprintHandler helper = new FingerprintHandler(this, newFragment);
helper.startAuth(fingerprintManager, cryptoObject);
}
}
}
}
}
@Override
protected void onResume() {
super.onResume();
Log.d("coinfolio", "Hello");
}
private void generateKey() throws FingerprintException
{
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyStore.load(null);
keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
keyGenerator.generateKey();
} catch (KeyStoreException
| NoSuchAlgorithmException
| NoSuchProviderException
| InvalidAlgorithmParameterException
| CertificateException
| IOException e) {
e.printStackTrace();
throw new FingerprintException(e);
}
}
public boolean initCipher()
{
try {
cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("Failed to get Cipher", e);
}
try {
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME, null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (KeyPermanentlyInvalidatedException e) {
return false;
} catch (KeyStoreException | CertificateException
| UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Failed to init Cipher", e);
}
}
private class FingerprintException extends Exception {
public FingerprintException(Exception e)
{
super(e);
}
}
/**
@ -358,6 +240,15 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class ExchangePreferenceFragment extends PreferenceFragment {
private static final String KEY_NAME = "NAUKEY";
private Cipher cipher;
private KeyStore keyStore;
private KeyGenerator keyGenerator;
private FingerprintManager.CryptoObject cryptoObject;
private FingerprintManager fingerprintManager;
private KeyguardManager keyguardManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
@ -366,10 +257,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
setHasOptionsMenu(true);
bindPreferenceSummaryToValue(findPreference("hitbtc_publickey"));
bindPreferenceSummaryToValue(findPreference("hitbtc_privatekey"));
bindPreferenceSummaryToValue(findPreference("binance_publickey"));
bindPreferenceSummaryToValue(findPreference("hitbtc_privatekey"));
bindPreferenceSummaryToValue(findPreference("binance_privatekey"));
startFingerprintProtocol();
}
@Override
@ -381,6 +274,123 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
return super.onOptionsItemSelected(item);
}
private void startFingerprintProtocol()
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this.getContext());
FingerprintDialogFragment newFragment = FingerprintDialogFragment.newInstance();
if(preferences.getBoolean("enable_fingerprint", false))
{
newFragment.setCancelable(false);
newFragment.show(getFragmentManager(), "dialog");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
keyguardManager = (KeyguardManager) this.getActivity().getSystemService(KEYGUARD_SERVICE);
fingerprintManager = (FingerprintManager) this.getActivity().getSystemService(FINGERPRINT_SERVICE);
try {
if(!fingerprintManager.isHardwareDetected())
{
this.getActivity().findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
if(ActivityCompat.checkSelfPermission(this.getContext(), Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED)
{
this.getActivity().findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
if(!fingerprintManager.hasEnrolledFingerprints())
{
this.getActivity().findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
if(!keyguardManager.isKeyguardSecure())
{
this.getActivity().findViewById(R.id.fingerprint_switch).setVisibility(View.GONE);
}
else
{
try {
generateKey();
} catch (FingerprintException e) {
e.printStackTrace();
}
if(initCipher())
{
cryptoObject = new FingerprintManager.CryptoObject(cipher);
FingerprintHandler helper = new FingerprintHandler(this.getContext(), newFragment);
helper.startAuth(fingerprintManager, cryptoObject);
}
}
} catch (NullPointerException e) {
e.printStackTrace();
}
}
}
}
private void generateKey() throws FingerprintException
{
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyStore.load(null);
keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
keyGenerator.generateKey();
} catch (KeyStoreException
| NoSuchAlgorithmException
| NoSuchProviderException
| InvalidAlgorithmParameterException
| CertificateException
| IOException e) {
e.printStackTrace();
throw new FingerprintException(e);
}
}
public boolean initCipher()
{
try {
cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("Failed to get Cipher", e);
}
try {
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME, null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (KeyPermanentlyInvalidatedException e) {
return false;
} catch (KeyStoreException | CertificateException
| UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Failed to init Cipher", e);
}
}
private class FingerprintException extends Exception {
public FingerprintException(Exception e)
{
super(e);
}
}
}
/**

View File

@ -20,6 +20,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.mattprecious.swirl.SwirlView;
import com.nauk.coinfolio.Activities.SettingsActivity;
@ -42,11 +44,15 @@ public class FingerprintDialogFragment extends DialogFragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_fingerprint_scanner, container);
//getDialog().getWindow().setLayout(getResources().getDimensionPixelSize(R.dimen.fingerprint_dialog_width), getResources().getDimensionPixelSize(R.dimen.fingerprint_dialog_height));
((Button) view.findViewById(R.id.cancelButton)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
getActivity().finish();
}
});
@ -65,17 +71,20 @@ public class FingerprintDialogFragment extends DialogFragment{
swirlView.setState(SwirlView.State.ON);
}
public void wrongFingerprint()
public void wrongFingerprint(String errorString)
{
((SwirlView) this.getView().findViewById(R.id.swirl)).clearColorFilter();
((SwirlView) this.getView().findViewById(R.id.swirlBackground)).clearColorFilter();
((SwirlView) this.getView().findViewById(R.id.swirl)).setState(SwirlView.State.ERROR);
((SwirlView) this.getView().findViewById(R.id.swirlBackground)).setState(SwirlView.State.ERROR);
((TextView) this.getView().findViewById(R.id.fingerprint_error)).setText(errorString);
}
public void resetFingerprint()
{
((SwirlView) this.getView().findViewById(R.id.swirlBackground)).setState(SwirlView.State.ON);
((TextView) this.getView().findViewById(R.id.fingerprint_error)).setText("");
SwirlView swirlView = this.getView().findViewById(R.id.swirl);
swirlView.clearColorFilter();

View File

@ -40,32 +40,58 @@ public class FingerprintHandler extends FingerprintManager.AuthenticationCallbac
public void onAuthenticationError(int errMsgId, CharSequence errString)
{
//Toast.makeText(context, "Authentification error\n" + errString, Toast.LENGTH_LONG).show();
dialogFragment.wrongFingerprint();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
dialogFragment.resetFingerprint();
}
}, 500);
if(dialogFragment.isVisible())
{
dialogFragment.wrongFingerprint("Error");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(dialogFragment.isVisible())
{
dialogFragment.resetFingerprint();
}
}
}, 500);
}
}
@Override
public void onAuthenticationFailed()
{
//Toast.makeText(context, "Authentification failed", Toast.LENGTH_LONG).show();
dialogFragment.wrongFingerprint();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
dialogFragment.resetFingerprint();
}
}, 500);
if(dialogFragment.isVisible())
{
dialogFragment.wrongFingerprint("Wrong fingerprint");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(dialogFragment.isVisible())
{
dialogFragment.resetFingerprint();
}
}
}, 500);
}
}
@Override
public void onAuthenticationHelp(int helpMsgIf, CharSequence helpString)
{
Toast.makeText(context, "Authentification help\n" + helpString, Toast.LENGTH_LONG).show();
//Toast.makeText(context, "Authentification help\n" + helpString, Toast.LENGTH_LONG).show();
if(dialogFragment.isVisible())
{
dialogFragment.wrongFingerprint(helpString.toString());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(dialogFragment.isVisible())
{
dialogFragment.resetFingerprint();
}
}
}, 500);
}
}
@Override

View File

@ -1,44 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout 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:id="@+id/edit_name"
android:layout_width="250dp"
android:layout_height="125dp"
android:layout_gravity="center"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<TextView
android:id="@+id/fingerprint_textview"
android:text="@string/pref_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<FrameLayout
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="@dimen/fingerprint_dialog_width"
android:layout_height="wrap_content"
android:layout_gravity="center">
android:orientation="vertical">
<com.mattprecious.swirl.SwirlView
android:id="@+id/swirlBackground"
android:layout_width="@dimen/swirl_size"
android:layout_height="@dimen/swirl_size"
tools:swirl_state="on"/>
<TextView
android:id="@+id/fingerprint_textview"
android:text="@string/fingerprint_dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_margin="@dimen/mainText"/>
<com.mattprecious.swirl.SwirlView
android:id="@+id/swirl"
android:layout_width="@dimen/swirl_size"
android:layout_height="@dimen/swirl_size"
tools:swirl_state="on"/>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
</FrameLayout>
<com.mattprecious.swirl.SwirlView
android:id="@+id/swirlBackground"
android:layout_width="@dimen/swirl_size"
android:layout_height="@dimen/swirl_size"
tools:swirl_state="on"/>
<Button
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fingerprint_dialog_cancel"
style="?android:attr/borderlessButtonStyle"
android:layout_gravity="end"/>
<com.mattprecious.swirl.SwirlView
android:id="@+id/swirl"
android:layout_width="@dimen/swirl_size"
android:layout_height="@dimen/swirl_size"
tools:swirl_state="on"/>
</LinearLayout>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="end">
<TextView
android:id="@+id/fingerprint_error"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:gravity="center"
android:textColor="@color/red"
android:layout_margin="5dp"/>
<Button
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/fingerprint_dialog_cancel"
style="?android:attr/borderlessButtonStyle"
android:layout_alignParentEnd="true"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -13,4 +13,6 @@
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="swirl_size">60dp</dimen>
<dimen name="fingerprint_dialog_height">125dp</dimen>
<dimen name="fingerprint_dialog_width">250dp</dimen>
</resources>

View File

@ -147,5 +147,6 @@
<string name="title_activity_main">MainActivity</string>
<string name="fingerprint_dialog_cancel">Cancel</string>
<string name="fingerprint_dialog_title">Verify your fingerprint to continue</string>
</resources>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="exchange">
<SwitchPreference
android:id="@+id/fingerprint_switch"