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.PreferenceActivity;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.RingtonePreference; import android.preference.RingtonePreference;
import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyPermanentlyInvalidatedException;
@ -65,14 +66,6 @@ import javax.crypto.SecretKey;
*/ */
public class SettingsActivity extends AppCompatPreferenceActivity { 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 * A preference value change listener that updates the preference's summary
* to reflect its new value. * to reflect its new value.
@ -140,6 +133,9 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
finish(); finish();
return true; return true;
} }
Log.d("coinfolio", "hello");
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -169,120 +165,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setupActionBar(); 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) @TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class ExchangePreferenceFragment extends PreferenceFragment { 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 @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
{ {
@ -366,10 +257,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
setHasOptionsMenu(true); setHasOptionsMenu(true);
bindPreferenceSummaryToValue(findPreference("hitbtc_publickey")); bindPreferenceSummaryToValue(findPreference("hitbtc_publickey"));
bindPreferenceSummaryToValue(findPreference("hitbtc_privatekey"));
bindPreferenceSummaryToValue(findPreference("binance_publickey")); bindPreferenceSummaryToValue(findPreference("binance_publickey"));
bindPreferenceSummaryToValue(findPreference("hitbtc_privatekey"));
bindPreferenceSummaryToValue(findPreference("binance_privatekey")); bindPreferenceSummaryToValue(findPreference("binance_privatekey"));
startFingerprintProtocol();
} }
@Override @Override
@ -381,6 +274,123 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
} }
return super.onOptionsItemSelected(item); 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.ViewGroup;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.mattprecious.swirl.SwirlView; import com.mattprecious.swirl.SwirlView;
import com.nauk.coinfolio.Activities.SettingsActivity; import com.nauk.coinfolio.Activities.SettingsActivity;
@ -42,11 +44,15 @@ public class FingerprintDialogFragment extends DialogFragment{
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{ {
View view = inflater.inflate(R.layout.fragment_fingerprint_scanner, container); 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() { ((Button) view.findViewById(R.id.cancelButton)).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
dismiss();
getActivity().finish(); getActivity().finish();
} }
}); });
@ -65,17 +71,20 @@ public class FingerprintDialogFragment extends DialogFragment{
swirlView.setState(SwirlView.State.ON); 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.swirl)).clearColorFilter();
((SwirlView) this.getView().findViewById(R.id.swirlBackground)).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.swirl)).setState(SwirlView.State.ERROR);
((SwirlView) this.getView().findViewById(R.id.swirlBackground)).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() public void resetFingerprint()
{ {
((SwirlView) this.getView().findViewById(R.id.swirlBackground)).setState(SwirlView.State.ON); ((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 swirlView = this.getView().findViewById(R.id.swirl);
swirlView.clearColorFilter(); swirlView.clearColorFilter();

View File

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

View File

@ -1,18 +1,24 @@
<?xml version="1.0" encoding="utf-8"?> <?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:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/edit_name" android:layout_width="match_parent"
android:layout_width="250dp" android:layout_height="match_parent"
android:layout_height="125dp" android:layout_gravity="center">
android:layout_gravity="center"
<LinearLayout
android:layout_width="@dimen/fingerprint_dialog_width"
android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/fingerprint_textview" android:id="@+id/fingerprint_textview"
android:text="@string/pref_fingerprint" android:text="@string/fingerprint_dialog_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_margin="@dimen/mainText"/>
<FrameLayout <FrameLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -33,12 +39,33 @@
</FrameLayout> </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 <Button
android:id="@+id/cancelButton" android:id="@+id/cancelButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/fingerprint_dialog_cancel" android:text="@string/fingerprint_dialog_cancel"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
android:layout_gravity="end"/> android:layout_alignParentEnd="true"/>
</LinearLayout> </LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

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

View File

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

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?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 <SwitchPreference
android:id="@+id/fingerprint_switch" android:id="@+id/fingerprint_switch"