diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f451b05a..ade4445b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -154,7 +154,7 @@ repositories { dependencies { // Testing testImplementation("junit:junit:4.13.2") - testImplementation("org.json:json:20231013") + testImplementation("org.json:json:20240303") androidTestImplementation("androidx.test:core") implementation("androidx.test.ext:junit-ktx:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5") @@ -163,10 +163,10 @@ dependencies { // Android Core & Lifecycle implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") - implementation("androidx.navigation:navigation-ui-ktx:2.7.6") + implementation("androidx.navigation:navigation-ui-ktx:2.7.7") implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") - implementation("androidx.navigation:navigation-fragment-ktx:2.7.6") + implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") // Design & UI implementation("jp.wasabeef:glide-transformations:4.3.0") diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 48798ce6..1d25ba97 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3 import android.animation.ValueAnimator +import android.app.Activity import android.content.ComponentName import android.content.Context import android.content.Intent @@ -62,9 +63,11 @@ import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings import com.lagradost.cloudstream3.APIHolder.initAll import com.lagradost.cloudstream3.APIHolder.updateHasTrailers +import com.lagradost.cloudstream3.AcraApplication.Companion.context import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.CommonActivity.loadThemes import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent @@ -135,6 +138,7 @@ 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.deviceHasPasswordPinLock +import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.main @@ -1226,10 +1230,9 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu changeStatusBarState(isEmulatorSettings()) /** Biometric stuff for users without accounts **/ - val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_key), false) val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1 - if (isTruePhone() && authEnabled && noAccounts) { + if (isTruePhone() && isAuthEnabled(this) && noAccounts) { if (deviceHasPasswordPinLock(this)) { startBiometricAuthentication(this, R.string.biometric_authentication_title, false) @@ -1787,6 +1790,14 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu binding?.navHostFragment?.isInvisible = false } + override fun onAuthenticationError() { + try { + finish() + } + catch (e:Exception) { + print(e) + } + } 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 1dae5a0f..2836fae4 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 @@ -22,6 +22,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueP import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.utils.BiometricAuthenticator import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock +import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex @@ -46,7 +47,6 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet ) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_key), false) val skipStartup = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false ) || accounts.count() <= 1 @@ -54,7 +54,7 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet fun askBiometricAuth() { - if (isTruePhone() && authEnabled) { + if (isTruePhone() && isAuthEnabled(this)) { if (deviceHasPasswordPinLock(this)) { startBiometricAuthentication( this, @@ -187,4 +187,8 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet override fun onAuthenticationSuccess() { Log.i(BiometricAuthenticator.TAG,"Authentication successful in AccountSelectActivity") } + + override fun onAuthenticationError() { + finish() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt index 14f11c1e..15eef0a9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt @@ -12,6 +12,7 @@ import androidx.core.view.isVisible import androidx.fragment.app.FragmentActivity import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceManager +import androidx.preference.SwitchPreferenceCompat import androidx.recyclerview.widget.RecyclerView import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent @@ -30,19 +31,22 @@ import com.lagradost.cloudstream3.syncproviders.AuthAPI import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI import com.lagradost.cloudstream3.syncproviders.OAuth2API import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref +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.setPaddingBottom import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.BackupUtils +import com.lagradost.cloudstream3.utils.BiometricAuthenticator +import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogText import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.setImage -class SettingsAccount : PreferenceFragmentCompat() { +class SettingsAccount : PreferenceFragmentCompat(),BiometricAuthenticator.BiometricAuthCallback { companion object { /** Used by nginx plugin too */ fun showLoginInfo( @@ -250,6 +254,31 @@ class SettingsAccount : PreferenceFragmentCompat() { } } + private fun updateAuthPreference(enabled: Boolean) { + val biometricKey = getString(R.string.biometric_key) + + PreferenceManager.getDefaultSharedPreferences(context ?: requireContext()).edit() + .putBoolean(biometricKey, enabled).apply() + findPreference(biometricKey)?.isChecked = enabled + } + + override fun onAuthenticationError() { + updateAuthPreference(!isAuthEnabled(context ?: requireContext())) + } + + override fun onAuthenticationSuccess() { + if (isAuthEnabled(context?: return)) { + updateAuthPreference(true) + BackupUtils.backup(activity) + activity?.showBottomDialogText( + getString(R.string.biometric_setting), + getString(R.string.biometric_warning).html() + ) { onDialogDismissedEvent } + } else { + updateAuthPreference(false) + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setUpToolbar(R.string.category_account) @@ -260,23 +289,27 @@ class SettingsAccount : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { hideKeyboard() setPreferencesFromResource(R.xml.settings_account, rootKey) + // hide preference on tvs and emulators + if (!isTruePhone()) { + getPref(R.string.biometric_key)?.isVisible = false + } getPref(R.string.biometric_key)?.setOnPreferenceClickListener { - val authEnabled = PreferenceManager.getDefaultSharedPreferences( - context ?: return@setOnPreferenceClickListener false - ) - .getBoolean(getString(R.string.biometric_key), false) + val ctx = context ?: return@setOnPreferenceClickListener false - if (authEnabled) { - BackupUtils.backup(activity) - val title = activity?.getString(R.string.biometric_setting) - val warning = activity?.getString(R.string.biometric_warning) - activity?.showBottomDialogText( - title as String, - warning.html() - ) { onDialogDismissedEvent } + if (BiometricAuthenticator.deviceHasPasswordPinLock(ctx)) { + BiometricAuthenticator.startBiometricAuthentication( + activity?: requireActivity(), + R.string.biometric_authentication_title, + false + ) + BiometricAuthenticator.promptInfo?.let { + BiometricAuthenticator.authCallback = this + BiometricAuthenticator.biometricPrompt?.authenticate(it) + } } - true + + false } val syncApis = 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 de9b9963..21b499b3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt @@ -12,7 +12,9 @@ import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL import androidx.biometric.BiometricPrompt import androidx.core.content.ContextCompat +import androidx.core.content.ContextCompat.getString import androidx.fragment.app.FragmentActivity +import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R @@ -21,7 +23,6 @@ object BiometricAuthenticator { private const val MAX_FAILED_ATTEMPTS = 3 private var failedAttempts = 0 const val TAG = "cs3Auth" - private var biometricManager: BiometricManager? = null var biometricPrompt: BiometricPrompt? = null var promptInfo: BiometricPrompt.PromptInfo? = null @@ -42,15 +43,8 @@ object BiometricAuthenticator { super.onAuthenticationError(errorCode, errString) showToast("$errString") Log.e(TAG, "$errorCode") - failedAttempts++ - - if (failedAttempts >= MAX_FAILED_ATTEMPTS) { - failedAttempts = 0 - activity.finish() - } else { - failedAttempts = 0 - activity.finish() - } + authCallback?.onAuthenticationError() + //activity.finish() } override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { @@ -153,7 +147,7 @@ object BiometricAuthenticator { // function to start authentication in any fragment or activity fun startBiometricAuthentication(activity: Activity, title: Int, setDeviceCred: Boolean) { initializeBiometrics(activity) - + authCallback = activity as? BiometricAuthCallback if (isBiometricHardWareAvailable()) { authCallback = activity as? BiometricAuthCallback authenticationDialog(activity, title, setDeviceCred) @@ -171,7 +165,15 @@ object BiometricAuthenticator { } } + fun isAuthEnabled(ctx: Context):Boolean { + return ctx.let { + PreferenceManager.getDefaultSharedPreferences(ctx) + .getBoolean(getString(ctx, R.string.biometric_key), false) + } + } + interface BiometricAuthCallback { fun onAuthenticationSuccess() + fun onAuthenticationError() } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b5dae57b..ab56a849 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -249,7 +249,7 @@ Search Library Accounts and Security - Updates and backup + Updates and Backup Info Advanced Search Gives you the search results separated by provider @@ -611,7 +611,7 @@ Tracks Audio tracks Video tracks - Apply on Restart + Restart the app to see changes. Restart Stop Safe mode on