diff --git a/README.md b/README.md index af607d6..a457236 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ## Min SDK Version - 15 -PFLockScreen - Lock Screen Library for Android Application. Library support **pin code** and **fingerprint** authorization for API level 23+. +PFLockScreen - Lock Screen Library for Android Application. Library support **pin code** and **biometric** authorization for API level 23+.

alt textalt textalt text @@ -72,7 +72,7 @@ PFFLockScreenConfiguration.Builder(this).setMode(PFFLockScreenConfiguration.MODE ```java PFFLockScreenConfiguration.Builder builder = new PFFLockScreenConfiguration.Builder(this) .setTitle("Unlock") - .setUseFingerprint(true). + .setUseBiometric(true). .setMode(PFFLockScreenConfiguration.MODE_AUTH) .setCodeLength(6) .setLeftButton("Can't remeber", @@ -87,7 +87,7 @@ PFFLockScreenConfiguration.Builder builder = new PFFLockScreenConfiguration.Buil *setTitle(String)* - set custom string on the top of the screen. -*setUseFingerprint(boolean)* - by default fingerprint button will be shown for all device 23+ with a fingerprint sensor. If you don't want use fingerprint at all set *false*. +*setUseBiometric(boolean)* - by default fingerprint(biometric authentication) button will be shown for all device 23+ with a fingerprint sensor and/or face recognition. If you don't want use biometric authentication at all set *false*. *setMode(PFLockScreenMode)* - MODE_CREATE or MODE_AUTH. See details above. *setCodeLength(int)* - set the length of the pin code. By default, length is 4. Minimum length is 4. *setLeftButton(String, View.OnClickListener)* - set string for the left button and ClickListener. diff --git a/app/build.gradle b/app/build.gradle index e0d8a56..790fb2b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,11 +20,11 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.2-alpha01' - androidTestImplementation 'androidx.test:runner:1.1.2-alpha01' - androidTestImplementation 'androidx.test:rules:1.1.2-alpha01' + implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta6' + testImplementation 'junit:junit:4.13' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-rc01' + androidTestImplementation 'androidx.test:runner:1.3.0-rc01' + androidTestImplementation 'androidx.test:rules:1.3.0-rc01' implementation project(':pflockscreen') } diff --git a/app/src/main/java/com/beautycoder/applicationlockscreenexample/MainActivity.java b/app/src/main/java/com/beautycoder/applicationlockscreenexample/MainActivity.java index 8ac9e5d..553a0e9 100644 --- a/app/src/main/java/com/beautycoder/applicationlockscreenexample/MainActivity.java +++ b/app/src/main/java/com/beautycoder/applicationlockscreenexample/MainActivity.java @@ -42,13 +42,13 @@ public void onNewCodeValidationFailed() { @Override public void onCodeInputSuccessful() { - Toast.makeText(MainActivity.this, "Code successfull", Toast.LENGTH_SHORT).show(); + Toast.makeText(MainActivity.this, "Code successful", Toast.LENGTH_SHORT).show(); showMainFragment(); } @Override - public void onFingerprintSuccessful() { - Toast.makeText(MainActivity.this, "Fingerprint successfull", Toast.LENGTH_SHORT).show(); + public void onBiometricAuthSuccessful() { + Toast.makeText(MainActivity.this, "Biometric authentication successful", Toast.LENGTH_SHORT).show(); showMainFragment(); } @@ -58,8 +58,8 @@ public void onPinLoginFailed() { } @Override - public void onFingerprintLoginFailed() { - Toast.makeText(MainActivity.this, "Fingerprint failed", Toast.LENGTH_SHORT).show(); + public void onBiometricAuthLoginFailed() { + Toast.makeText(MainActivity.this, "Biometric authentication failed", Toast.LENGTH_SHORT).show(); } }; @@ -89,7 +89,8 @@ private void showLockScreenFragment(boolean isPinExist) { .setLeftButton("Can't remeber") .setNewCodeValidation(true) .setNewCodeValidationTitle("Please input code again") - .setUseFingerprint(true); + .setAutoShowBiometric(true) + .setUseBiometric(true); final PFLockScreenFragment fragment = new PFLockScreenFragment(); fragment.setOnLeftButtonClickListener(new View.OnClickListener() { diff --git a/pflockscreen/build.gradle b/pflockscreen/build.gradle index db00931..d8abca7 100644 --- a/pflockscreen/build.gradle +++ b/pflockscreen/build.gradle @@ -32,6 +32,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' + implementation "androidx.biometric:biometric:1.0.1" + //Livecycles & ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" diff --git a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/PFFLockScreenConfiguration.java b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/PFFLockScreenConfiguration.java index 6d0c5b5..bc8483f 100644 --- a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/PFFLockScreenConfiguration.java +++ b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/PFFLockScreenConfiguration.java @@ -15,8 +15,9 @@ public class PFFLockScreenConfiguration implements Serializable { private String mLeftButton = ""; private String mNextButton = ""; - private boolean mUseFingerprint = false; - private boolean mAutoShowFingerprint = false; + private boolean mUseBiometric = false; + private boolean mAutoShowBiometric = false; + private int mBiometricBackground = -1; private String mTitle = ""; private int mMode = MODE_AUTH; private int mCodeLength = 4; @@ -29,8 +30,9 @@ public class PFFLockScreenConfiguration implements Serializable { private PFFLockScreenConfiguration(Builder builder) { mLeftButton = builder.mLeftButton; mNextButton = builder.mNextButton; - mUseFingerprint = builder.mUseFingerprint; - mAutoShowFingerprint = builder.mAutoShowFingerprint; + mUseBiometric = builder.mUseBiometric; + mAutoShowBiometric = builder.mAutoShowBiometric; + mBiometricBackground = builder.mBiometricBackground; mTitle = builder.mTitle; mMode = builder.mMode; mCodeLength = builder.mCodeLength; @@ -49,12 +51,16 @@ public String getNextButton() { return mNextButton; } - public boolean isUseFingerprint() { - return mUseFingerprint; + public boolean isUseBiometric() { + return mUseBiometric; } - public boolean isAutoShowFingerprint() { - return mAutoShowFingerprint; + public boolean isAutoShowBiometric() { + return mAutoShowBiometric; + } + + public int getBiometricBackground() { + return mBiometricBackground; } public String getTitle() { @@ -94,8 +100,9 @@ public static class Builder { private String mLeftButton = ""; private String mNextButton = ""; - private boolean mUseFingerprint = false; - private boolean mAutoShowFingerprint = false; + private boolean mUseBiometric = false; + private boolean mAutoShowBiometric = false; + private int mBiometricBackground = -1; private String mTitle = ""; private int mMode = 0; private int mCodeLength = 4; @@ -125,13 +132,18 @@ public Builder setNextButton(String nextButton) { return this; } - public Builder setUseFingerprint(boolean useFingerprint) { - mUseFingerprint = useFingerprint; + public Builder setUseBiometric(boolean useBiometric) { + mUseBiometric = useBiometric; + return this; + } + + public Builder setAutoShowBiometric(boolean autoShowBiometric) { + mAutoShowBiometric = autoShowBiometric; return this; } - public Builder setAutoShowFingerprint(boolean autoShowFingerprint) { - mAutoShowFingerprint = autoShowFingerprint; + public Builder setBiometricBackground(int biometricBackground) { + mBiometricBackground = biometricBackground; return this; } diff --git a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/BiometricUIStarter.java b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/BiometricUIStarter.java new file mode 100644 index 0000000..c52c2bf --- /dev/null +++ b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/BiometricUIStarter.java @@ -0,0 +1,67 @@ +package com.beautycoder.pflockscreen.fragments; + +import android.content.Context; +import android.content.res.Resources; + +import androidx.biometric.BiometricManager; +import androidx.biometric.BiometricPrompt; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + +import com.beautycoder.pflockscreen.R; + +import java.util.concurrent.Executor; + +public class BiometricUIStarter { + private final BiometricManager biometricManager; + private final BiometricPrompt biometricPrompt; + private String title = "Biometric Authentication"; + private String description; + private boolean confirmationRequired; + private String usePin; + + public BiometricUIStarter(BiometricManager bioManager, Context context, Fragment fragment, BiometricPrompt.AuthenticationCallback callback) { + biometricManager = bioManager; + usePin = context.getResources().getString(R.string.use_pin_pf); + biometricPrompt = instanceOfBiometricPrompt(context, fragment, callback); + } + + private BiometricPrompt instanceOfBiometricPrompt(Context context, Fragment fragment, BiometricPrompt.AuthenticationCallback callback) { + Executor executor = ContextCompat.getMainExecutor(context); + return new BiometricPrompt(fragment, executor ,callback); + } + + public boolean isBiometricAuthAvailable() { + return biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS; + } + + public boolean isBiometricAuthNotSet() { + return biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED; + } + + private BiometricPrompt.PromptInfo getPromptInfo() { + return new BiometricPrompt.PromptInfo.Builder() + .setTitle(title) + .setDescription(description) + .setDeviceCredentialAllowed(false) + .setNegativeButtonText(usePin) + .setConfirmationRequired(confirmationRequired) + .build(); + } + + public void startUI() { + biometricPrompt.authenticate(getPromptInfo()); + } + + public void setTitle(String title) { + this.title = title; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setConfirmationRequired(boolean confirmationRequired) { + this.confirmationRequired = confirmationRequired; + } +} diff --git a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFFingerprintAuthDialogFragment.java b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFFingerprintAuthDialogFragment.java deleted file mode 100644 index 829d4a9..0000000 --- a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFFingerprintAuthDialogFragment.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.beautycoder.pflockscreen.fragments; - -import android.content.Context; -import android.os.Build; -import android.os.Bundle; -import androidx.annotation.RequiresApi; -import androidx.fragment.app.DialogFragment; -import androidx.core.hardware.fingerprint.FingerprintManagerCompat; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -import com.beautycoder.pflockscreen.R; - -/** - * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password - * authentication if fingerprint is not available. - */ -@RequiresApi(api = Build.VERSION_CODES.M) -public class PFFingerprintAuthDialogFragment extends DialogFragment { - - private Button mCancelButton; - private View mFingerprintContent; - - private Stage mStage = Stage.FINGERPRINT; - - private FingerprintManagerCompat.CryptoObject mCryptoObject; - - private PFFingerprintUIHelper mFingerprintCallback; - - private Context mContext; - - private PFFingerprintAuthListener mAuthListener; - - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Do not create a new Fragment when the Activity is re-created such as orientation changes. - setRetainInstance(true); - setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog); - } - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - getDialog().setTitle(getString(R.string.sign_in_pf)); - View v = inflater.inflate(R.layout.view_pf_fingerprint_dialog_container, container, - false); - mCancelButton = v.findViewById(R.id.cancel_button); - mCancelButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - dismiss(); - } - }); - - mFingerprintContent = v.findViewById(R.id.fingerprint_container); - - - FingerprintManagerCompat manager = FingerprintManagerCompat.from(getContext()); - mFingerprintCallback = new PFFingerprintUIHelper(manager, - (ImageView) v.findViewById(R.id.fingerprint_icon), - (TextView) v.findViewById(R.id.fingerprint_status), - mAuthListener); - updateStage(); - return v; - } - - @Override - public void onResume() { - super.onResume(); - if (mStage == Stage.FINGERPRINT) { - mFingerprintCallback.startListening(mCryptoObject); - } - } - - public void setStage(Stage stage) { - mStage = stage; - } - - @Override - public void onPause() { - super.onPause(); - mFingerprintCallback.stopListening(); - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - mContext = context; - } - - /** - * Sets the crypto object to be passed in when authenticating with fingerprint. - */ - /*public void setCryptoObject(FingerprintManagerCompat.CryptoObject cryptoObject) { - mCryptoObject = cryptoObject; - }*/ - - - private void updateStage() { - switch (mStage) { - case FINGERPRINT: - mCancelButton.setText(R.string.cancel_pf); - mFingerprintContent.setVisibility(View.VISIBLE); - break; - } - } - - - public void setAuthListener(PFFingerprintAuthListener authListener) { - mAuthListener = authListener; - } - - /** - * Enumeration to indicate which authentication method the user is trying to authenticate with. - */ - public enum Stage { - FINGERPRINT - } -} diff --git a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFFingerprintUIHelper.java b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFFingerprintUIHelper.java deleted file mode 100644 index 5158682..0000000 --- a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFFingerprintUIHelper.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.beautycoder.pflockscreen.fragments; - -import android.os.Build; -import androidx.annotation.RequiresApi; -import androidx.core.hardware.fingerprint.FingerprintManagerCompat; -import androidx.core.os.CancellationSignal; -import android.widget.ImageView; -import android.widget.TextView; - -import com.beautycoder.pflockscreen.R; - - -/** - * Created by aleksandr on 2018/02/10. - */ - -@RequiresApi(api = Build.VERSION_CODES.M) -public class PFFingerprintUIHelper extends FingerprintManagerCompat.AuthenticationCallback { - - private static final long ERROR_TIMEOUT_MILLIS = 1600; - private static final long SUCCESS_DELAY_MILLIS = 200; - - private final FingerprintManagerCompat mFingerprintManager; - private final ImageView mIcon; - private final TextView mErrorTextView; - private final PFFingerprintAuthListener mCallback; - private CancellationSignal mCancellationSignal; - - private boolean mSelfCancelled; - - public PFFingerprintUIHelper(FingerprintManagerCompat fingerprintManager, - ImageView icon, TextView errorTextView, - PFFingerprintAuthListener callback) { - super(); - mFingerprintManager = fingerprintManager; - mIcon = icon; - mErrorTextView = errorTextView; - mCallback = callback; - } - - public boolean isFingerprintAuthAvailable() { - // The line below prevents the false positive inspection from Android Studio - // noinspection ResourceType - return mFingerprintManager.isHardwareDetected() - && mFingerprintManager.hasEnrolledFingerprints(); - } - - public void startListening(FingerprintManagerCompat.CryptoObject cryptoObject) { - if (!isFingerprintAuthAvailable()) { - return; - } - mCancellationSignal = new CancellationSignal(); - mSelfCancelled = false; - // The line below prevents the false positive inspection from Android Studio - // noinspection ResourceType - mFingerprintManager.authenticate( - cryptoObject, 0, mCancellationSignal, this, null); - mIcon.setImageResource(R.drawable.ic_fp_40px_pf); - } - - public void stopListening() { - if (mCancellationSignal != null) { - mSelfCancelled = true; - mCancellationSignal.cancel(); - mCancellationSignal = null; - } - } - - @Override - public void onAuthenticationError(int errMsgId, CharSequence errString) { - if (!mSelfCancelled) { - showError(errString); - mIcon.postDelayed(new Runnable() { - @Override - public void run() { - mCallback.onError(); - } - }, ERROR_TIMEOUT_MILLIS); - } - } - - @Override - public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { - showError(helpString); - } - - @Override - public void onAuthenticationFailed() { - showError(mIcon.getResources().getString( - R.string.fingerprint_not_recognized_pf)); - } - - @Override - public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { - mErrorTextView.removeCallbacks(mResetErrorTextRunnable); - mIcon.setImageResource(R.drawable.ic_fingerprint_success_pf); - mErrorTextView.setTextColor( - mErrorTextView.getResources().getColor(R.color.success_color, null)); - mErrorTextView.setText( - mErrorTextView.getResources().getString(R.string.fingerprint_success_pf)); - mIcon.postDelayed(new Runnable() { - @Override - public void run() { - mCallback.onAuthenticated(); - } - }, SUCCESS_DELAY_MILLIS); - } - - private void showError(CharSequence error) { - mIcon.setImageResource(R.drawable.ic_fingerprint_error_pf); - mErrorTextView.setText(error); - mErrorTextView.setTextColor( - mErrorTextView.getResources().getColor(R.color.warning_color, null)); - mErrorTextView.removeCallbacks(mResetErrorTextRunnable); - mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS); - } - - private Runnable mResetErrorTextRunnable = new Runnable() { - @Override - public void run() { - mErrorTextView.setTextColor( - mErrorTextView.getResources().getColor(R.color.hint_color, null)); - mErrorTextView.setText( - mErrorTextView.getResources().getString(R.string.fingerprint_hint_pf)); - mIcon.setImageResource(R.drawable.ic_fp_40px_pf); - } - }; - -} diff --git a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFLockScreenFragment.java b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFLockScreenFragment.java index 5ef925c..813a62c 100644 --- a/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFLockScreenFragment.java +++ b/pflockscreen/src/main/java/com/beautycoder/pflockscreen/fragments/PFLockScreenFragment.java @@ -3,6 +3,8 @@ import android.app.AlertDialog; import androidx.annotation.NonNull; +import androidx.biometric.BiometricManager; +import androidx.biometric.BiometricPrompt; import androidx.lifecycle.Observer; import android.content.Context; import android.content.DialogInterface; @@ -18,9 +20,11 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.Button; +import android.widget.RelativeLayout; import android.widget.TextView; import com.beautycoder.pflockscreen.PFFLockScreenConfiguration; @@ -39,20 +43,18 @@ public class PFLockScreenFragment extends Fragment { private static final String TAG = PFLockScreenFragment.class.getName(); - private static final String FINGERPRINT_DIALOG_FRAGMENT_TAG = "FingerprintDialogFragment"; - private static final String INSTANCE_STATE_CONFIG = "com.beautycoder.pflockscreen.instance_state_config"; - private View mFingerprintButton; + private View mBiometricAuthButton; private View mDeleteButton; private TextView mLeftButton; private Button mNextButton; private PFCodeView mCodeView; private TextView titleView; - private boolean mUseFingerPrint = true; - private boolean mFingerprintHardwareDetected = false; + private boolean mUseBiometricAuth = true; + private boolean mBiometricAuthHardwareDetected = false; private boolean mIsCreateMode = false; private OnPFLockScreenCodeCreateListener mCodeCreateListener; @@ -61,6 +63,9 @@ public class PFLockScreenFragment extends Fragment { private String mCodeValidation = ""; private String mEncodedPinCode = ""; + private BiometricUIStarter bioAuth; + private View biometricView = null; + private PFFLockScreenConfiguration mConfiguration; private View mRootView; @@ -78,7 +83,7 @@ public void onSaveInstanceState(@NonNull Bundle outState) { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.fragment_lock_screen_pf, container, + View view = inflater.inflate(R.layout.fragment_lock_screen_pf, container, false); if (mConfiguration == null) { @@ -87,7 +92,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, ); } - mFingerprintButton = view.findViewById(R.id.button_finger_print); + mBiometricAuthButton = view.findViewById(R.id.button_finger_print); mDeleteButton = view.findViewById(R.id.button_delete); mLeftButton = view.findViewById(R.id.button_left); @@ -95,33 +100,42 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, mDeleteButton.setOnClickListener(mOnDeleteButtonClickListener); mDeleteButton.setOnLongClickListener(mOnDeleteButtonOnLongClickListener); - mFingerprintButton.setOnClickListener(mOnFingerprintClickListener); + mBiometricAuthButton.setOnClickListener(mOnBiometricAuthClickListener); mCodeView = view.findViewById(R.id.code_view); initKeyViews(view); mCodeView.setListener(mCodeListener); - if (!mUseFingerPrint) { - mFingerprintButton.setVisibility(View.GONE); + if (!mUseBiometricAuth) { + mBiometricAuthButton.setVisibility(View.GONE); } - mFingerprintHardwareDetected = isFingerprintApiAvailable(getContext()); mRootView = view; applyConfiguration(mConfiguration); + boolean instantBiometricScan = mConfiguration.isUseBiometric() && mConfiguration.isAutoShowBiometric(); + boolean createMode = mConfiguration.getMode() == PFFLockScreenConfiguration.MODE_CREATE; + BiometricManager bioManager = BiometricManager.from(getContext()); + BiometricPrompt.AuthenticationCallback callback = createCallback(); + bioAuth = new BiometricUIStarter(bioManager, getContext(), this, callback); + mBiometricAuthHardwareDetected = bioAuth.isBiometricAuthAvailable(); + bioAuth.setTitle(getString(R.string.sign_in_pf)); + + if (mBiometricAuthHardwareDetected && instantBiometricScan && !createMode) { + bioAuth.setConfirmationRequired(true); + bioAuth.startUI(); + int backgroundID = mConfiguration.getBiometricBackground(); + if (backgroundID != -1) { //this will set a new view over the pin fragment which makes it easier to go back from this view + biometricView = inflater.inflate(backgroundID, container, false); + ((RelativeLayout)view.findViewById(R.id.fragment_pf)).addView(biometricView); + } + } + return view; } - @Override - public void onStart() { - if (!mIsCreateMode && mUseFingerPrint && mConfiguration.isAutoShowFingerprint() && - isFingerprintApiAvailable(getActivity()) && isFingerprintsExists(getActivity())) { - mOnFingerprintClickListener.onClick(mFingerprintButton); - } - super.onStart(); - } public void setConfiguration(PFFLockScreenConfiguration configuration) { this.mConfiguration = configuration; @@ -145,16 +159,16 @@ private void applyConfiguration(PFFLockScreenConfiguration configuration) { mNextButton.setText(configuration.getNextButton()); } - mUseFingerPrint = configuration.isUseFingerprint(); - if (!mUseFingerPrint) { - mFingerprintButton.setVisibility(View.GONE); + mUseBiometricAuth = configuration.isUseBiometric(); + if (!mUseBiometricAuth) { + mBiometricAuthButton.setVisibility(View.GONE); mDeleteButton.setVisibility(View.VISIBLE); } mIsCreateMode = mConfiguration.getMode() == PFFLockScreenConfiguration.MODE_CREATE; if (mIsCreateMode) { mLeftButton.setVisibility(View.GONE); - mFingerprintButton.setVisibility(View.GONE); + mBiometricAuthButton.setVisibility(View.GONE); } if (mIsCreateMode) { @@ -212,39 +226,18 @@ public boolean onLongClick(View v) { } }; - private final View.OnClickListener mOnFingerprintClickListener = new View.OnClickListener() { + private final View.OnClickListener mOnBiometricAuthClickListener = new View.OnClickListener() { @Override public void onClick(View v) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || - !isFingerprintApiAvailable(getActivity())) { + if (bioAuth.isBiometricAuthAvailable()) { + bioAuth.setConfirmationRequired(false); + bioAuth.startUI(); return; } - - if (!isFingerprintsExists(getActivity())) { - showNoFingerprintDialog(); - return; + if (bioAuth.isBiometricAuthNotSet()) { + showNoBiometricAuthDialog(); } - - final PFFingerprintAuthDialogFragment fragment - = new PFFingerprintAuthDialogFragment(); - fragment.show(getFragmentManager(), FINGERPRINT_DIALOG_FRAGMENT_TAG); - fragment.setAuthListener(new PFFingerprintAuthListener() { - @Override - public void onAuthenticated() { - if (mLoginListener != null) { - mLoginListener.onFingerprintSuccessful(); - } - fragment.dismiss(); - } - - @Override - public void onError() { - if (mLoginListener != null) { - mLoginListener.onFingerprintLoginFailed(); - } - } - }); } }; @@ -259,17 +252,17 @@ private void configureRightButton(int codeLength) { } if (codeLength > 0) { - mFingerprintButton.setVisibility(View.GONE); + mBiometricAuthButton.setVisibility(View.GONE); mDeleteButton.setVisibility(View.VISIBLE); mDeleteButton.setEnabled(true); return; } - if (mUseFingerPrint && mFingerprintHardwareDetected) { - mFingerprintButton.setVisibility(View.VISIBLE); + if (mUseBiometricAuth && mBiometricAuthHardwareDetected) { + mBiometricAuthButton.setVisibility(View.VISIBLE); mDeleteButton.setVisibility(View.GONE); } else { - mFingerprintButton.setVisibility(View.GONE); + mBiometricAuthButton.setVisibility(View.GONE); mDeleteButton.setVisibility(View.VISIBLE); } @@ -277,16 +270,7 @@ private void configureRightButton(int codeLength) { } - private boolean isFingerprintApiAvailable(Context context) { - return FingerprintManagerCompat.from(context).isHardwareDetected(); - } - - private boolean isFingerprintsExists(Context context) { - return FingerprintManagerCompat.from(context).hasEnrolledFingerprints(); - } - - - private void showNoFingerprintDialog() { + private void showNoBiometricAuthDialog() { new AlertDialog.Builder(getContext()) .setTitle(R.string.no_fingerprints_title_pf) .setMessage(R.string.no_fingerprints_message_pf) @@ -432,6 +416,41 @@ public void setOnLeftButtonClickListener(View.OnClickListener onLeftButtonClickL this.mOnLeftButtonClickListener = onLeftButtonClickListener; } + private BiometricPrompt.AuthenticationCallback createCallback() { + return new BiometricPrompt.AuthenticationCallback() { + @Override + public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { + super.onAuthenticationError(errorCode, errString); + if (errorCode == 13 || errorCode == 10) { //13 for "use pin" button and 10 for clicking above the biometricPrompt + if (biometricView != null) { + ((ViewManager) biometricView.getParent()).removeView(biometricView); + biometricView = null; + } + return; + } + if (mLoginListener != null) { + mLoginListener.onBiometricAuthLoginFailed(); + } + } + + @Override + public void onAuthenticationFailed() { + super.onAuthenticationFailed(); + if (mLoginListener != null) { + mLoginListener.onBiometricAuthLoginFailed(); + } + } + + @Override + public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { + super.onAuthenticationSucceeded(result); + if (mLoginListener != null) { + mLoginListener.onBiometricAuthSuccessful(); + } + } + }; + } + /*private void showFingerprintAlertDialog(Context context) { new AlertDialog.Builder(context).setTitle("Fingerprint").setMessage( "Would you like to use fingerprint for future login?") @@ -514,7 +533,7 @@ public interface OnPFLockScreenLoginListener { /** * Callback method for successful login attempt with fingerprint. */ - void onFingerprintSuccessful(); + void onBiometricAuthSuccessful(); /** * Callback method for unsuccessful login attempt with pin code. @@ -524,7 +543,7 @@ public interface OnPFLockScreenLoginListener { /** * Callback method for unsuccessful login attempt with fingerprint. */ - void onFingerprintLoginFailed(); + void onBiometricAuthLoginFailed(); } diff --git a/pflockscreen/src/main/res/layout/fragment_lock_screen_pf.xml b/pflockscreen/src/main/res/layout/fragment_lock_screen_pf.xml index 1bc3807..badb3c8 100644 --- a/pflockscreen/src/main/res/layout/fragment_lock_screen_pf.xml +++ b/pflockscreen/src/main/res/layout/fragment_lock_screen_pf.xml @@ -2,7 +2,9 @@ + android:layout_height="wrap_content" + android:clickable="true" + android:focusable="true"> + PFLockScreen + Abbrechen + Benutze PIN + Einloggen + OK + Weiter + Vergessen? + Pin eingeben oder biometrische Authentifizierung nutzen + Einstellungen + Keine biometrischen Daten gefunden. Bitte fügen + Sie in den Einstellungen welche hinzu. + Keine biometrischen Daten gefunden + + Fingerabdruck bestätigen + Sensor berühren + Fingerabdruck icon + \ No newline at end of file diff --git a/pflockscreen/src/main/res/values/strings.xml b/pflockscreen/src/main/res/values/strings.xml index aba9064..5e82ea7 100644 --- a/pflockscreen/src/main/res/values/strings.xml +++ b/pflockscreen/src/main/res/values/strings.xml @@ -6,13 +6,11 @@ OK Next Forgot? - Input pin code or use fingerprint + Input pin code or use biometric authentication Settings - No fingerprints found. Please add fingerprints in the settings if you want to use this authorization method." - "No fingerprints found" + No biometric data found. Please add fingerprints or face recognition in the settings if you want to use this authorization method." + "No biometric data found" - Fingerprint not recognized. Try again - Fingerprint recognized Confirm fingerprint to continue Touch sensor Fingerprint icon