public class FingerprintActivity extends Activity implements OnClickListener {
private FingerprintManager manager;
private CancellationSignal signal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fingerprint);
findViewById(R.id.Fingerprint).setOnClickListener(this);
manager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
}
@SuppressLint("NewApi")
@Override
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.Fingerprint:
if (!manager.isHardwareDetected()) {
Toast.makeText(this, "设备不支持", Toast.LENGTH_LONG).show();
return;
}
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (!keyguardManager.isKeyguardSecure()) {
Toast.makeText(this, "请设置图案锁", Toast.LENGTH_LONG).show();
return;
}
if (!manager.hasEnrolledFingerprints()) {
Toast.makeText(this, "请设置指纹", Toast.LENGTH_LONG).show();
return;
}
try {
CryptoObjectHelper helper = new CryptoObjectHelper();
signal = new CancellationSignal();
/**
*FingerprintManager.authenticate(CryptoObject crypto,
* CancellationSignal cancel,
* int flags, AuthenticationCallback callback,
* Handler handler) parameter explanation
* 1. crypto this It is an object of encryption class, and the fingerprint scanner will use this object to determine the validity of the authentication result.
* This object can be null, but in this case, it means that the app unconditionally trusts the result of the authentication,
* Although theoretically this process may be attacked and data can be tampered with,
* This is a risk that the app must take in this case . Therefore, it is recommended not to set this parameter to null.
* The instantiation of this class is a bit cumbersome, mainly implemented using the security interface of javax
* CryptoObjectHelper can be directly referenced by the written tool class
* 2.cancel This is an object of the CancellationSignal class,
* This object is used to cancel the current scanning operation when the fingerprint reader scans the user's fingerprint,
* If not canceled , then the fingerprint scanner will scan until the timeout (usually 30s, depending on the specific manufacturer's implementation),
* this will consume more power. It is recommended that this parameter not be set to null.
* 3.flags flag bit, according to the document description above, this bit should be 0 temporarily, and this flag bit should be reserved for future use.
* 4.callback This is an object of FingerprintManager.AuthenticationCallback class,
* This is the most important parameter in this interface except the first parameter.
* When the system completes the fingerprint authentication process (failure or success),
* it will call back the interface in this object to notify the app of the result of the authentication. This parameter cannot be NULL
* 5.handler This is an object of the Handler class. If this parameter is not null,
* FingerprintManager will use the looper in this handler to process messages from the fingerprint recognition hardware.
* Generally speaking, this parameter is not required for development, and can be set to null directly,
* because FingerprintManager will use the app's main looper to process it by default.
*
* */
manager.authenticate(helper.buildCryptoObject(), signal, 0, new MyAuthCallback(FingerprintActivity.this), null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
default:
break;
}
}
@SuppressLint("NewApi")
@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
signal.cancel();
}
}
MyAuthCallback class
public class MyAuthCallback extends AuthenticationCallback{
private Context context;
public MyAuthCallback(Context context){
this.context = context;
}
/**
* This interface will be called back after successful authentication. We can prompt the user to authenticate successfully in this method.
* It needs to be explained here that if our CryptoObject is not null when we call authenticate above,
* then we can get the Cypher object through AuthenticationResult in this method and then call its doFinal method.
* The doFinal method will check whether the result will be intercepted or tampered with, and if so will throw an exception.
* When we find these exceptions, we should treat the authentication as a failure. It is recommended that everyone do this for security.
*
* */
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
// TODO Auto-generated method stub
super.onAuthenticationSucceeded(result);
Toast.makeText(context, "success", Toast.LENGTH_LONG).show();
// AuthenticationResult to get the Cypher object and call its doFinal method.
//The doFinal method will check whether the result will be intercepted or tampered with, and if so will throw an exception.
//When we find these exceptions, we should treat the authentication as a failure. It is recommended that everyone do this for safety.
try {
byte[] by =result.getCryptoObject().getCipher().doFinal();
String date = new String(by, "UTF-8");
Log.e("TAG", date);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*
* This interface will call back only when the system fingerprint authentication fails. Note that the authentication failure here is not the same as the authentication error above,
* although the result is not authentication. Authentication failure means that all information is collected completely and there is no abnormality,
* but the fingerprint does not match the previously registered fingerprint; but authentication error means that there is an error in the process of collection or authentication,
* such as fingerprint sensor Abnormal work, etc. That is to say, authentication failure is an expected normal situation, while authentication error is an unpredictable abnormal situation.
*
* */
@Override
public void onAuthenticationFailed() {
// TODO Auto-generated method stub
super.onAuthenticationFailed();
Toast.makeText(context, "Authentication failed", Toast.LENGTH_LONG).show();
}
/**
* The above authentication failure is an abnormal situation in the authentication process. We say that the situation is because of an unrecoverable error.
* And our OnAuthenticationHelp method here is only called when there is an exception that can be replied.
* What is a recoverable exception? A common example is:
* The finger is moving too fast, when we put the finger on the sensor, if we remove the finger quickly,
* then the fingerprint sensor may only collect part of the information, so the authentication will fail .
* But this bug is recoverable, so just prompt the user to press the fingerprint again and don't remove it too quickly.
*
* */
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
// TODO Auto-generated method stub
super.onAuthenticationHelp(helpCode, helpString);
Toast.makeText(context, "Press the fingerprint again", Toast.LENGTH_LONG ).show();
}
/**
* This interface will only be called when an unrecoverable error occurs in the system fingerprint authentication, and the parameter errorCode gives the error code.
* identifies the cause of the error. All the app can do at this point is to prompt the user to try again.
*
* **/
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
// TODO Auto-generated method stub
super.onAuthenticationError(errorCode, errString);
Toast.makeText(context, "Authentication exception", Toast.LENGTH_LONG) .show();
}
}
/**
* Reference link: http://blog.csdn.net/baniel01/article/details/51991764
*
* **/
public class CryptoObjectHelper {
// This can be key name you want. Should be unique for the app.
static final String KEY_NAME = "com.createchance.android.sample.fingerprint_authentication_key";
// We always use this keystore on Android.
static final String KEYSTORE_NAME = "AndroidKeyStore";
// Should be no need to change these values.
static final String KEY_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
static final String TRANSFORMATION = KEY_ALGORITHM + "/" +
BLOCK_MODE + "/" +
ENCRYPTION_PADDING;
final KeyStore _keystore;
public CryptoObjectHelper() throws Exception
{
_keystore = KeyStore.getInstance(KEYSTORE_NAME);
_keystore.load(null);
}
//FingerprintManagerCompat.CryptoObject buildCryptoObject()
public FingerprintManager.CryptoObject buildCryptoObject() throws Exception{
Cipher cipher = createCipher(true);
return new FingerprintManager.CryptoObject(cipher);
}
Cipher createCipher(boolean retry) throws Exception{
Key key = GetKey();
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
try
{
cipher.init(Cipher.ENCRYPT_MODE | Cipher.DECRYPT_MODE, key);
} catch(KeyPermanentlyInvalidatedException e)
{
_keystore.deleteEntry(KEY_NAME);
if(retry)
{
createCipher(false);
} else
{
throw new Exception("Could not create the cipher for fingerprint authentication.", e);
}
}
return cipher;
}
Key GetKey() throws Exception
{
Key secretKey;
if(!_keystore.isKeyEntry(KEY_NAME))
{
CreateKey();
}
secretKey = _keystore.getKey(KEY_NAME, null);
return secretKey;
}
void CreateKey() throws Exception
{
KeyGenerator keyGen = KeyGenerator.getInstance(KEY_ALGORITHM, KEYSTORE_NAME);
KeyGenParameterSpec keyGenSpec =
new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(BLOCK_MODE)
.setEncryptionPaddings(ENCRYPTION_PADDING)
.setUserAuthenticationRequired(true)
.build();
keyGen.init(keyGenSpec);
keyGen.generateKey();
}
}
Address: https://git.oschina.net/qswwers/Android-Fingerprint.git