체크 리스트앱에 비밀번호를 설정해서 쓰는데, 매번 숫자 쳐넣기가 귀찮아서 OS에 등록한 지문을 체크하도록 개선 했다.
지문은 안드로이드 6.0 Api 23(마시멜로) 부터 사용가능하다.
FingerprintUiHelper.kt를 구현
typealias FingerprintUiHelperCallback = () -> Unit
@TargetApi(Build.VERSION_CODES.M)
class FingerprintUiHelper(
private val fingerprintManager: FingerprintManager?,
private val icon: ImageView,
private val errorTextView: TextView
) : FingerprintManager.AuthenticationCallback() {
companion object {
private const val ERROR_TIMEOUT_MILLIS: Long = 1600
}
private var cancellationSignal: CancellationSignal? = null
private var selfCancelled: Boolean = false
private val isFingerprintAuthAvailable: Boolean
get() = fingerprintManager?.isHardwareDetected == true && fingerprintManager.hasEnrolledFingerprints()
private var resetErrorTextRunnable: Runnable = Runnable {
errorTextView.text = errorTextView.resources.getString(R.string.fingerprint_hint)
icon.setImageResource(R.drawable.ic_fp_40px)
}
var onAuthenticatedCallback: FingerprintUiHelperCallback = {}
var onErrorCallback: FingerprintUiHelperCallback = {}
fun startListening(): Boolean {
if (!isFingerprintAuthAvailable) {
return false
}
cancellationSignal = CancellationSignal()
selfCancelled = false
fingerprintManager
?.authenticate(null, cancellationSignal, 0 /* flags */, this, null)
icon.setImageResource(R.drawable.ic_fp_40px)
return true
}
fun stopListening() {
if (cancellationSignal != null) {
selfCancelled = true
cancellationSignal!!.cancel()
cancellationSignal = null
}
}
override fun onAuthenticationError(errMsgId: Int, errString: CharSequence) {
if (!selfCancelled) {
showError(errString)
icon.postDelayed({ onErrorCallback() }, ERROR_TIMEOUT_MILLIS)
}
}
override fun onAuthenticationHelp(helpMsgId: Int, helpString: CharSequence) {
showError(helpString)
}
override fun onAuthenticationFailed() {
showError(
icon.resources.getString(
R.string.fingerprint_not_recognized
)
)
}
override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
errorTextView.removeCallbacks(resetErrorTextRunnable)
icon.setImageResource(R.drawable.ic_fingerprint_success)
errorTextView.text = errorTextView.resources.getString(R.string.fingerprint_success)
onAuthenticatedCallback()
}
private fun showError(error: CharSequence) {
icon.setImageResource(R.drawable.ic_fingerprint_error)
errorTextView.text = error
errorTextView.removeCallbacks(resetErrorTextRunnable)
errorTextView.postDelayed(resetErrorTextRunnable, ERROR_TIMEOUT_MILLIS)
}
}
리소스나 스트링은 github을 참고하면 되기에 생략한다.
지문을 체크하는 View를 하나 만든다. 지문 체크 페이지의 특정 viewGroup에 addView하여 지문 기능을 Injection한다.
FingerprintAuthView.kt
@TargetApi(Build.VERSION_CODES.M)
class FingerprintAuthView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
private var fingerprintUiHelper: FingerprintUiHelper
private var layout: View = LayoutInflater.from(context).inflate(R.layout.fingerprint_auth_view, null)
init {
fingerprintUiHelper = FingerprintUiHelper(
context.getSystemService(FingerprintManager::class.java),
layout.findViewById(R.id.passcode_fingerprint_image),
layout.findViewById(R.id.passcode_fingerprint_status)
)
addView(
layout,
LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
)
layout.visibility = View.GONE
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val isStarted = fingerprintUiHelper.startListening()
layout.visibility = if (isStarted) View.VISIBLE else View.GONE
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
fingerprintUiHelper.stopListening()
}
fun setOnAuthenticated(callback: FingerprintUiHelperCallback) {
fingerprintUiHelper.onAuthenticatedCallback = callback;
}
fun setOnError(callback: FingerprintUiHelperCallback) {
fingerprintUiHelper.onErrorCallback = callback
}
}
AuthView를 injection해보자.
PassCodeActivity.java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& mMode == PassCodeMode.Confirm) {
LinearLayout linearLayout = findViewById(R.id.linearLayout1);
FingerprintAuthView authView = new FingerprintAuthView(this);
authView.setOnAuthenticated(new Function0<Unit>() {
@Override
public Unit invoke() {
finish();
return null;
}
});
linearLayout.addView(authView);
}
권한 추가도 잊지말것
<uses-permission android:name="android.permission.USE_FINGERPRINT" />