rewrite and improve biometric authenticator

This commit is contained in:
IndusAryan 2024-02-19 00:15:16 +05:30
parent 0f80d9950c
commit b75441eb3a
6 changed files with 160 additions and 112 deletions

View file

@ -113,6 +113,7 @@ import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.ui.search.SearchFragment import com.lagradost.cloudstream3.ui.search.SearchFragment
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTruePhone
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
@ -133,9 +134,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
import com.lagradost.cloudstream3.utils.BackupUtils.backup import com.lagradost.cloudstream3.utils.BackupUtils.backup
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
import com.lagradost.cloudstream3.utils.BiometricAuthenticator import com.lagradost.cloudstream3.utils.BiometricAuthenticator
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.TAG import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isTruePhone import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.promptInfo
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.getKey
@ -1176,7 +1176,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false) val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
setContentView(newLocalBinding.root) setContentView(newLocalBinding.root)
if(isTrueTvSettings() && ANIMATED_OUTLINE) { if (isTrueTvSettings() && ANIMATED_OUTLINE) {
TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline) TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline)
newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener { newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {
TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true) TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true)
@ -1188,14 +1188,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
newLocalBinding.focusOutline.isVisible = false newLocalBinding.focusOutline.isVisible = false
} }
if(isTrueTvSettings()) { if (isTrueTvSettings()) {
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus -> newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
centerView(newFocus) centerView(newFocus)
} }
} }
ActivityMainBinding.bind(newLocalBinding.root) // this may crash ActivityMainBinding.bind(newLocalBinding.root) // this may crash
} else { } else {
val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false) val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false)
@ -1213,12 +1211,20 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_enabled_key), false) val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_enabled_key), false)
val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1 val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1
if (isTruePhone() && authEnabled && noAccounts ) { if (isTruePhone() && authEnabled && noAccounts) {
if (deviceHasPasswordPinLock(this)) {
startBiometricAuthentication(this,
R.string.biometric_authentication_title,
false
)
BiometricAuthenticator.initializeBiometrics(this@MainActivity, this) BiometricAuthenticator.biometricPrompt.authenticate(BiometricAuthenticator.promptInfo)
BiometricAuthenticator.checkBiometricAvailability()
BiometricAuthenticator.biometricPrompt.authenticate(promptInfo) // hide background while authenticating, Sorry moms & dads 🙏
binding?.navHostFragment?.isInvisible = true // hide background while authenticating binding?.navHostFragment?.isInvisible = true
} else {
showToast(R.string.phone_not_secured, Toast.LENGTH_LONG)
}
} }
// Automatically enable jsdelivr if cant connect to raw.githubusercontent.com // Automatically enable jsdelivr if cant connect to raw.githubusercontent.com
@ -1760,7 +1766,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
) )
} }
override fun onAuthenticationSuccess() { /** Biometric stuff **/ /** Biometric stuff **/
override fun onAuthenticationSuccess() {
// make background (nav host fragment) visible again // make background (nav host fragment) visible again
binding?.navHostFragment?.isInvisible = false binding?.navHostFragment?.isInvisible = false
} }

View file

@ -3,6 +3,8 @@ package com.lagradost.cloudstream3.ui.account
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@ -17,8 +19,11 @@ import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.AutofitRecyclerView import com.lagradost.cloudstream3.ui.AutofitRecyclerView
import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_EDIT_ACCOUNT import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_EDIT_ACCOUNT
import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_SELECT_ACCOUNT import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_SELECT_ACCOUNT
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTruePhone
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.BiometricAuthenticator import com.lagradost.cloudstream3.utils.BiometricAuthenticator
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts
import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex
import com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount import com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount
@ -43,19 +48,24 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_enabled_key), false) val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_enabled_key), false)
val skipStartup = settingsManager.getBoolean( val skipStartup = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false
getString(R.string.skip_startup_account_select_key),
false
) || accounts.count() <= 1 ) || accounts.count() <= 1
viewModel = ViewModelProvider(this)[AccountViewModel::class.java] viewModel = ViewModelProvider(this)[AccountViewModel::class.java]
fun askBiometricAuth() { fun askBiometricAuth() {
if (BiometricAuthenticator.isTruePhone() && authEnabled) { if (isTruePhone() && authEnabled) {
BiometricAuthenticator.initializeBiometrics(this@AccountSelectActivity, this) if (deviceHasPasswordPinLock(this)) {
BiometricAuthenticator.checkBiometricAvailability() startBiometricAuthentication(
BiometricAuthenticator.biometricPrompt.authenticate(BiometricAuthenticator.promptInfo) this,
R.string.biometric_authentication_title,
false
)
BiometricAuthenticator.biometricPrompt.authenticate(BiometricAuthenticator.promptInfo)
}
} else {
showToast(R.string.phone_not_secured, Toast.LENGTH_LONG)
} }
} }
@ -178,7 +188,8 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
startActivity(mainIntent) startActivity(mainIntent)
finish() // Finish the account selection activity finish() // Finish the account selection activity
} }
override fun onAuthenticationSuccess() { override fun onAuthenticationSuccess() {
//ask github.com/IndusAryan if confusion occurs Log.i(BiometricAuthenticator.TAG,"Authentication successful in AccountSelectActivity")
} }
} }

View file

@ -19,6 +19,7 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.MainSettingsBinding import com.lagradost.cloudstream3.databinding.MainSettingsBinding
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
@ -155,6 +156,11 @@ class SettingsFragment : Fragment() {
return getLayoutInt() == 2 return getLayoutInt() == 2
} }
// phone exclusive
fun isTruePhone(): Boolean {
return !isTrueTvSettings() && !isTvSettings() && context?.isEmulatorSettings() != true
}
private fun Context.isAutoTv(): Boolean { private fun Context.isAutoTv(): Boolean {
val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager? val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager?
// AFT = Fire TV // AFT = Fire TV

View file

@ -5,7 +5,7 @@ import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast.LENGTH_SHORT
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
@ -13,139 +13,164 @@ import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
object BiometricAuthenticator { object BiometricAuthenticator {
private const val MAX_FAILED_ATTEMPTS = 3
private var failedAttempts = 0
const val TAG = "cs3Auth"
private lateinit var biometricManager: BiometricManager private lateinit var biometricManager: BiometricManager
lateinit var biometricPrompt: BiometricPrompt lateinit var biometricPrompt: BiometricPrompt
lateinit var promptInfo: BiometricPrompt.PromptInfo lateinit var promptInfo: BiometricPrompt.PromptInfo
const val TAG = "cs3Auth"
private var authCallback: BiometricAuthCallback? = null var authCallback: BiometricAuthCallback? = null // listen to authentication success
fun initializeBiometrics(activity: Activity, callback: BiometricAuthCallback) { private fun initializeBiometrics(activity: Activity) {
val executor = ContextCompat.getMainExecutor(activity) val executor = ContextCompat.getMainExecutor(activity)
authCallback = callback // to listen success authentication
biometricManager = BiometricManager.from(activity) biometricManager = BiometricManager.from(activity)
biometricPrompt = BiometricPrompt(activity as AppCompatActivity, executor, object : BiometricPrompt.AuthenticationCallback() { if (!::promptInfo.isInitialized) {
initBiometricPrompt(
activity as AppCompatActivity,
R.string.biometric_authentication_title,
false
)
}
biometricPrompt = BiometricPrompt(
activity as AppCompatActivity,
executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString) super.onAuthenticationError(errorCode, errString)
Log.d(TAG, "Authentication error: $errString") showToast("$errString", LENGTH_SHORT)
Log.i(TAG, "$errorCode")
activity.finish() activity.finish()
failedAttempts++
if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
failedAttempts = 0
activity.finish()
} else {
failedAttempts = 0
MainActivity().finish()
}
} }
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result) super.onAuthenticationSucceeded(result)
Log.d(TAG, "Biometric succeeded.") failedAttempts = 0
unblockMain() //to make background visible after authenticating authCallback?.onAuthenticationSuccess()
} }
override fun onAuthenticationFailed() { override fun onAuthenticationFailed() {
super.onAuthenticationFailed() super.onAuthenticationFailed()
Log.d(TAG, "Authentication error") failedAttempts++
showToast(R.string.biometric_failed, Toast.LENGTH_SHORT) if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
activity.finish() failedAttempts = 0
activity.finish()
}
} }
}) })
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { private fun initBiometricPrompt(
activity: Activity,
title: Int,
setDeviceCred: Boolean,
) {
val description = activity.getString(R.string.biometric_prompt_description)
if (setDeviceCred) {
// For API level > 30, Newer API setAllowedAuthenticators is used
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
promptInfo = BiometricPrompt.PromptInfo.Builder() val authFlag = DEVICE_CREDENTIAL or BIOMETRIC_WEAK or BIOMETRIC_STRONG
.setTitle("Unlock CloudStream") promptInfo = BiometricPrompt.PromptInfo.Builder()
//.setSubtitle("Log in using your biometric credential") .setTitle(activity.getString(title))
//.setNegativeButtonText("Use account password") .setDescription(description)
.setAllowedAuthenticators(BIOMETRIC_WEAK or BIOMETRIC_STRONG or DEVICE_CREDENTIAL) .setAllowedAuthenticators(authFlag)
.build() .build()
} else {
} else if (context?.let { deviceHasPasswordPinLock(it) } == true) { @Suppress("DEPRECATION")
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(activity.getString(title))
.setDescription(description)
.setDeviceCredentialAllowed(true)
.build()
}
} else {
// fallback for A12+ when both fingerprint & Face unlock is absent but PIN is set
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
promptInfo = BiometricPrompt.PromptInfo.Builder() promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Unlock CloudStream") .setTitle(activity.getString(title))
.setDescription(description)
.setDeviceCredentialAllowed(true) .setDeviceCredentialAllowed(true)
.build() .build()
} }
} }
fun checkBiometricAvailability() { private fun isBiometricHardWareAvailable(): Boolean {
var result = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
when (biometricManager.canAuthenticate(
// Strong and device credential bundle cannot be checked at same time in API < A11 (R) DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK
when (biometricManager.canAuthenticate(BIOMETRIC_WEAK or BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) { )) {
BiometricManager.BIOMETRIC_SUCCESS -> BiometricManager.BIOMETRIC_SUCCESS -> result = true
Log.d(TAG, "App can authenticate.") BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false
Log.d(TAG, "No biometric sensor found.") BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false
Log.d(TAG, "Biometric authentication is currently unavailable.") }
} else {
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> @Suppress("DEPRECATION")
showToast(R.string.biometric_not_enrolled, Toast.LENGTH_LONG) when (biometricManager.canAuthenticate()) {
BiometricManager.BIOMETRIC_SUCCESS -> result = true
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false
showToast(R.string.biometric_update_required, Toast.LENGTH_LONG) BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true
showToast(R.string.biometric_unsupported, Toast.LENGTH_SHORT) BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true
BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false
BiometricManager.BIOMETRIC_STATUS_UNKNOWN ->
Log.e(TAG, "Unknown error encountered while authenticating fingerprint.")
} }
} }
else { return result
}
when (biometricManager.canAuthenticate(BIOMETRIC_WEAK or BIOMETRIC_STRONG)) { // only needed for Android 9 and below
fun deviceHasPasswordPinLock(context: Context?): Boolean {
val keyMgr =
context?.getSystemService(AppCompatActivity.KEYGUARD_SERVICE) as KeyguardManager
return keyMgr.isKeyguardSecure
}
BiometricManager.BIOMETRIC_SUCCESS -> fun startBiometricAuthentication(activity: Activity, title: Int, setDeviceCred: Boolean) {
Log.d(TAG, "App can authenticate using biometrics.") initializeBiometrics(activity)
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> if (isBiometricHardWareAvailable()) {
Log.d(TAG, "No biometric features available on this device.") authCallback = activity as? BiometricAuthCallback
initBiometricPrompt(activity, title, setDeviceCred)
biometricPrompt.authenticate(promptInfo)
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> } else {
Log.e(TAG, "Biometric features are currently unavailable.") if (deviceHasPasswordPinLock(activity)) {
authCallback = activity as? BiometricAuthCallback
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> initBiometricPrompt(activity, R.string.password_pin_authentication_title, true)
showToast(R.string.biometric_not_enrolled, Toast.LENGTH_LONG) biometricPrompt.authenticate(promptInfo)
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED ->
showToast(R.string.biometric_update_required, Toast.LENGTH_LONG)
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED ->
showToast(R.string.biometric_unsupported, Toast.LENGTH_SHORT)
BiometricManager.BIOMETRIC_STATUS_UNKNOWN ->
Log.d(TAG, "Unknown error encountered while authenticating fingerprint.")
} else {
showToast(R.string.biometric_unsupported, LENGTH_SHORT)
} }
} }
} }
// yes, this feature is phone exclusive
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 { interface BiometricAuthCallback {
fun onAuthenticationSuccess() fun onAuthenticationSuccess()
} }

View file

@ -532,7 +532,6 @@ object UIHelper {
WindowInsetsControllerCompat(window, View(this)).show(WindowInsetsCompat.Type.systemBars()) WindowInsetsControllerCompat(window, View(this)).show(WindowInsetsCompat.Type.systemBars())
} else {*/ /** WINDOW COMPAT IS BUGGY DUE TO FU*KED UP PLAYER AND TRAILERS **/ } else {*/ /** WINDOW COMPAT IS BUGGY DUE TO FU*KED UP PLAYER AND TRAILERS **/
Suppress("DEPRECATION")
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility =
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
//} //}

View file

@ -745,13 +745,13 @@
<string name="auto_rotate_video_desc">Enable automatic switching of screen orientation based on video orientation</string> <string name="auto_rotate_video_desc">Enable automatic switching of screen orientation based on video orientation</string>
<string name="auto_rotate_video">Auto rotate</string> <string name="auto_rotate_video">Auto rotate</string>
<!-- For Biometrics -->
<string name="biometric_authentication_title">Unlock CloudStream</string>
<string name="biometric_setting">Fingerprint sensor authentication</string> <string name="biometric_setting">Fingerprint sensor authentication</string>
<string name="biometric_success">Fingerprint authentication succeeded</string>
<string name="biometric_failed">Fingerprint authentication failed</string>
<string name="biometric_prompt_title">Unlock CloudStream</string>
<string name="biometric_not_enrolled">Please add fingerprint or screen lock or disable setting</string>
<string name="biometric_update_required">Please update software and security patches.</string>
<string name="biometric_unsupported">Biometric authentication is not supported on this device</string>
<string name="biometric_enabled_key" translatable="false">biometric_key</string> <string name="biometric_enabled_key" translatable="false">biometric_key</string>
<string name="password_pin_authentication_title">Password/PIN Authentication</string>
<string name="biometric_unsupported">Biometric authentication is not supported on this device</string>
<string name="phone_not_secured">Please disable fingerprint authentication if device has no lock.</string>
<string name="biometric_prompt_description">This window will close after few failed attempts. You\'ll have to restart the App.</string>
</resources> </resources>