diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index d9c6694f..10f2badc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -28,6 +28,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.children import androidx.core.view.isGone +import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.core.view.marginStart import androidx.fragment.app.FragmentActivity @@ -128,6 +129,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus import com.lagradost.cloudstream3.utils.BackupUtils.backup import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup import com.lagradost.cloudstream3.utils.BiometricAuthenticator +import com.lagradost.cloudstream3.utils.BiometricAuthenticator.TAG import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isTruePhone import com.lagradost.cloudstream3.utils.BiometricAuthenticator.promptInfo import com.lagradost.cloudstream3.utils.Coroutines.ioSafe @@ -166,7 +168,6 @@ import kotlin.math.absoluteValue import kotlin.reflect.KClass import kotlin.system.exitProcess - //https://github.com/videolan/vlc-android/blob/3706c4be2da6800b3d26344fc04fab03ffa4b860/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt#L1898 //https://wiki.videolan.org/Android_Player_Intents/ @@ -285,7 +286,7 @@ var app = Requests(responseParser = object : ResponseParser { defaultHeaders = mapOf("user-agent" to USER_AGENT) } -class MainActivity : AppCompatActivity(), ColorPickerDialogListener { +class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAuthenticator.BiometricAuthCallback { companion object { const val TAG = "MAINACT" const val ANIMATED_OUTLINE : Boolean = false @@ -1161,9 +1162,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1 if (isTruePhone() && authEnabled && noAccounts ) { - BiometricAuthenticator.initializeBiometrics(this@MainActivity) + + BiometricAuthenticator.initializeBiometrics(this@MainActivity, this) BiometricAuthenticator.checkBiometricAvailability() BiometricAuthenticator.biometricPrompt.authenticate(promptInfo) + binding?.navHostFragment?.isInvisible = true // hide background while authenticating } // Automatically enable jsdelivr if cant connect to raw.githubusercontent.com @@ -1621,6 +1624,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { ) } + override fun onAuthenticationSuccess() { /** Biometric stuff **/ + // make background (nav host fragment) visible again + binding?.navHostFragment?.isInvisible = false + } + private var backPressedCallback: OnBackPressedCallback? = null private fun attachBackPressedCallback() { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt index 693f0c56..77bbc837 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt @@ -24,7 +24,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex import com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute -class AccountSelectActivity : AppCompatActivity() { +class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.BiometricAuthCallback { lateinit var viewModel: AccountViewModel @@ -43,7 +43,6 @@ class AccountSelectActivity : AppCompatActivity() { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_enabled_key), false) - val skipStartup = settingsManager.getBoolean( getString(R.string.skip_startup_account_select_key), false @@ -54,7 +53,7 @@ class AccountSelectActivity : AppCompatActivity() { fun askBiometricAuth() { if (BiometricAuthenticator.isTruePhone() && authEnabled) { - BiometricAuthenticator.initializeBiometrics(this) + BiometricAuthenticator.initializeBiometrics(this@AccountSelectActivity, this) BiometricAuthenticator.checkBiometricAvailability() BiometricAuthenticator.biometricPrompt.authenticate(BiometricAuthenticator.promptInfo) } @@ -179,4 +178,7 @@ class AccountSelectActivity : AppCompatActivity() { startActivity(mainIntent) finish() // Finish the account selection activity } + override fun onAuthenticationSuccess() { + //ask github.com/IndusAryan if confusion occurs + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt index 6c1f068d..2bc17891 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt @@ -1,6 +1,8 @@ package com.lagradost.cloudstream3.utils import android.app.Activity +import android.app.KeyguardManager +import android.content.Context import android.os.Build import android.util.Log import android.widget.Toast @@ -25,8 +27,11 @@ object BiometricAuthenticator { lateinit var promptInfo: BiometricPrompt.PromptInfo const val TAG = "cs3Auth" - fun initializeBiometrics(activity: Activity) { + private var authCallback: BiometricAuthCallback? = null + + fun initializeBiometrics(activity: Activity, callback: BiometricAuthCallback) { val executor = ContextCompat.getMainExecutor(activity) + authCallback = callback // to listen success authentication biometricManager = BiometricManager.from(activity) biometricPrompt = BiometricPrompt(activity as AppCompatActivity, executor, object : BiometricPrompt.AuthenticationCallback() { @@ -40,6 +45,7 @@ object BiometricAuthenticator { override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) Log.d(TAG, "Biometric succeeded.") + unblockMain() //to make background visible after authenticating } override fun onAuthenticationFailed() { @@ -50,19 +56,29 @@ object BiometricAuthenticator { } }) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + promptInfo = BiometricPrompt.PromptInfo.Builder() - .setTitle("Unlock CloudStream") - //.setSubtitle("Log in using your biometric credential") - //.setNegativeButtonText("Use account password") - .setAllowedAuthenticators(BIOMETRIC_WEAK or BIOMETRIC_STRONG or DEVICE_CREDENTIAL) - .build() + .setTitle("Unlock CloudStream") + //.setSubtitle("Log in using your biometric credential") + //.setNegativeButtonText("Use account password") + .setAllowedAuthenticators(BIOMETRIC_WEAK or BIOMETRIC_STRONG or DEVICE_CREDENTIAL) + .build() + + } else if (context?.let { deviceHasPasswordPinLock(it) } == true) { + @Suppress("DEPRECATION") + promptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle("Unlock CloudStream") + .setDeviceCredentialAllowed(true) + .build() + } } fun checkBiometricAvailability() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - // Strong and credential bundle cannot be checked at same time in API < A11 (R) + // Strong and device credential bundle cannot be checked at same time in API < A11 (R) when (biometricManager.canAuthenticate(BIOMETRIC_WEAK or BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) { BiometricManager.BIOMETRIC_SUCCESS -> Log.d(TAG, "App can authenticate.") @@ -74,10 +90,10 @@ object BiometricAuthenticator { Log.d(TAG, "Biometric authentication is currently unavailable.") BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> - showToast(R.string.biometric_not_enrolled, Toast.LENGTH_SHORT) + showToast(R.string.biometric_not_enrolled, Toast.LENGTH_LONG) BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> - showToast(R.string.biometric_update_required, Toast.LENGTH_SHORT) + showToast(R.string.biometric_update_required, Toast.LENGTH_LONG) BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> showToast(R.string.biometric_unsupported, Toast.LENGTH_SHORT) @@ -92,25 +108,25 @@ object BiometricAuthenticator { when (biometricManager.canAuthenticate(BIOMETRIC_WEAK or BIOMETRIC_STRONG)) { BiometricManager.BIOMETRIC_SUCCESS -> - Log.d(TAG, "App can authenticate using biometrics.") + Log.d(TAG, "App can authenticate using biometrics.") BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> - Log.d(TAG, "No biometric features available on this device.") + Log.d(TAG, "No biometric features available on this device.") BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> - Log.e(TAG, "Biometric features are currently unavailable.") + Log.e(TAG, "Biometric features are currently unavailable.") BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> - Log.e(TAG, "Biometric features are currently unavailable.") + showToast(R.string.biometric_not_enrolled, Toast.LENGTH_LONG) BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> - showToast(R.string.biometric_update_required, Toast.LENGTH_SHORT) + showToast(R.string.biometric_update_required, Toast.LENGTH_LONG) BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> - showToast(R.string.biometric_unsupported, Toast.LENGTH_SHORT) + showToast(R.string.biometric_unsupported, Toast.LENGTH_SHORT) BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> - Log.d(TAG, "Unknown error encountered while authenticating fingerprint.") + Log.d(TAG, "Unknown error encountered while authenticating fingerprint.") } } @@ -120,4 +136,17 @@ object BiometricAuthenticator { fun isTruePhone(): Boolean { return !isTrueTvSettings() && !isTvSettings() && context?.isEmulatorSettings() != true } + + fun unblockMain() { + authCallback?.onAuthenticationSuccess() + } + + private fun deviceHasPasswordPinLock(con: Context): Boolean { + val keyManager = con.getSystemService(AppCompatActivity.KEYGUARD_SERVICE) as KeyguardManager + return keyManager.isKeyguardSecure + } + + interface BiometricAuthCallback { + fun onAuthenticationSuccess() + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dc981408..56a78cf1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -742,11 +742,11 @@ Enable automatic switching of screen orientation based on video orientation Auto rotate - Use Fingerprint sensor authentication + Fingerprint sensor authentication Fingerprint authentication succeeded Fingerprint authentication failed Unlock CloudStream - No biometric credentials are enrolled + Please add fingerprint or screen lock or disable setting Please update software and security patches. Biometric authentication is not supported on this device biometric_key