mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 19:49:33 +01:00
fix screen locking feature
Since most controllers were replaced by activities, the screen locking was temporarily broken. This commit fixes the screen locking to also work with the activities. Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
a08ed8205d
commit
7518fdbcd9
@ -194,6 +194,8 @@ dependencies {
|
|||||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:${lifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-runtime-ktx:${lifecycleVersion}"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${lifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${lifecycleVersion}"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${lifecycleVersion}"
|
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${lifecycleVersion}"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-process:${lifecycleVersion}"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-common:${lifecycleVersion}"
|
||||||
|
|
||||||
implementation 'androidx.biometric:biometric:1.1.0'
|
implementation 'androidx.biometric:biometric:1.1.0'
|
||||||
|
|
||||||
|
@ -234,6 +234,10 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".lock.LockedActivity"
|
||||||
|
android:theme="@style/AppTheme" />
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.PackageReplacedReceiver"
|
android:name=".receivers.PackageReplacedReceiver"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
* Nextcloud Talk application
|
* Nextcloud Talk application
|
||||||
*
|
*
|
||||||
* @author Mario Danic
|
* @author Mario Danic
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@ -37,7 +39,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
|
|||||||
import com.nextcloud.talk.events.CertificateEvent
|
import com.nextcloud.talk.events.CertificateEvent
|
||||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
import com.nextcloud.talk.utils.DisplayUtils
|
import com.nextcloud.talk.utils.DisplayUtils
|
||||||
import com.nextcloud.talk.utils.SecurityUtils
|
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
import com.nextcloud.talk.utils.ssl.TrustManager
|
import com.nextcloud.talk.utils.ssl.TrustManager
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
@ -78,6 +79,11 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
eventBus.register(this)
|
||||||
|
}
|
||||||
|
|
||||||
public override fun onResume() {
|
public override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
@ -86,10 +92,11 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (appPreferences.isScreenLocked) {
|
public override fun onStop() {
|
||||||
SecurityUtils.createKey(appPreferences.screenLockTimeout)
|
super.onStop()
|
||||||
}
|
eventBus.unregister(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setupSystemColors() {
|
fun setupSystemColors() {
|
||||||
@ -183,16 +190,6 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
|
showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
eventBus.register(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
eventBus.unregister(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = "BaseActivity"
|
private val TAG = "BaseActivity"
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* @author Mario Danic
|
* @author Mario Danic
|
||||||
* @author Andy Scherzinger
|
* @author Andy Scherzinger
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
* Copyright (C) 2021 Andy Scherzinger (infoi@andy-scherzinger.de)
|
* Copyright (C) 2021 Andy Scherzinger (infoi@andy-scherzinger.de)
|
||||||
* Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
|
* Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
|
||||||
*
|
*
|
||||||
@ -28,6 +30,9 @@ import android.os.Bundle
|
|||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import com.bluelinelabs.conductor.Conductor
|
import com.bluelinelabs.conductor.Conductor
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
@ -40,13 +45,13 @@ import com.nextcloud.talk.R
|
|||||||
import com.nextcloud.talk.api.NcApi
|
import com.nextcloud.talk.api.NcApi
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
import com.nextcloud.talk.chat.ChatActivity
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
import com.nextcloud.talk.controllers.LockedController
|
|
||||||
import com.nextcloud.talk.controllers.ServerSelectionController
|
import com.nextcloud.talk.controllers.ServerSelectionController
|
||||||
import com.nextcloud.talk.controllers.WebViewLoginController
|
import com.nextcloud.talk.controllers.WebViewLoginController
|
||||||
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
|
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
|
||||||
import com.nextcloud.talk.conversationlist.ConversationsListActivity
|
import com.nextcloud.talk.conversationlist.ConversationsListActivity
|
||||||
import com.nextcloud.talk.data.user.model.User
|
import com.nextcloud.talk.data.user.model.User
|
||||||
import com.nextcloud.talk.databinding.ActivityMainBinding
|
import com.nextcloud.talk.databinding.ActivityMainBinding
|
||||||
|
import com.nextcloud.talk.lock.LockedActivity
|
||||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||||
import com.nextcloud.talk.users.UserManager
|
import com.nextcloud.talk.users.UserManager
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
@ -82,6 +87,13 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||||||
Log.d(TAG, "onCreate: Activity: " + System.identityHashCode(this).toString())
|
Log.d(TAG, "onCreate: Activity: " + System.identityHashCode(this).toString())
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||||
|
override fun onStart(owner: LifecycleOwner) {
|
||||||
|
lockScreenIfConditionsApply()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Set the default theme to replace the launch screen theme.
|
// Set the default theme to replace the launch screen theme.
|
||||||
setTheme(R.style.AppTheme)
|
setTheme(R.style.AppTheme)
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
@ -126,6 +138,16 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun lockScreenIfConditionsApply() {
|
||||||
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||||
|
if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
|
||||||
|
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
|
||||||
|
val lockIntent = Intent(context, LockedActivity::class.java)
|
||||||
|
startActivity(lockIntent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun launchLoginScreen() {
|
private fun launchLoginScreen() {
|
||||||
if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
|
if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
|
||||||
router!!.pushController(
|
router!!.pushController(
|
||||||
@ -145,15 +167,18 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
|
||||||
Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
|
Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
|
||||||
|
super.onStart()
|
||||||
logRouterBackStack(router!!)
|
logRouterBackStack(router!!)
|
||||||
lockScreenIfConditionsApply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
Log.d(TAG, "onResume: Activity: " + System.identityHashCode(this).toString())
|
Log.d(TAG, "onResume: Activity: " + System.identityHashCode(this).toString())
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
|
if (appPreferences.isScreenLocked) {
|
||||||
|
SecurityUtils.createKey(appPreferences.screenLockTimeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
@ -295,23 +320,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lockScreenIfConditionsApply() {
|
|
||||||
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
|
||||||
if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
|
|
||||||
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
|
|
||||||
if (router != null && router!!.getControllerWithTag(LockedController.TAG) == null) {
|
|
||||||
router!!.pushController(
|
|
||||||
RouterTransaction.with(LockedController())
|
|
||||||
.pushChangeHandler(VerticalChangeHandler())
|
|
||||||
.popChangeHandler(VerticalChangeHandler())
|
|
||||||
.tag(LockedController.TAG)
|
|
||||||
)
|
|
||||||
logRouterBackStack(router!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
Log.d(TAG, "onNewIntent Activity: " + System.identityHashCode(this).toString())
|
Log.d(TAG, "onNewIntent Activity: " + System.identityHashCode(this).toString())
|
||||||
@ -346,9 +354,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (router!!.getControllerWithTag(LockedController.TAG) != null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!router!!.handleBack()) {
|
if (!router!!.handleBack()) {
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* @author Andy Scherzinger
|
|
||||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.nextcloud.talk.controllers
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.KeyguardManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import androidx.biometric.BiometricPrompt
|
|
||||||
import androidx.biometric.BiometricPrompt.PromptInfo
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import autodagger.AutoInjector
|
|
||||||
import com.nextcloud.talk.R
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
|
||||||
import com.nextcloud.talk.controllers.base.BaseController
|
|
||||||
import com.nextcloud.talk.controllers.util.viewBinding
|
|
||||||
import com.nextcloud.talk.databinding.ControllerLockedBinding
|
|
||||||
import com.nextcloud.talk.utils.DisplayUtils
|
|
||||||
import com.nextcloud.talk.utils.SecurityUtils
|
|
||||||
import java.util.concurrent.Executor
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
|
||||||
class LockedController : BaseController(R.layout.controller_locked) {
|
|
||||||
private val binding: ControllerLockedBinding? by viewBinding(ControllerLockedBinding::bind)
|
|
||||||
|
|
||||||
override val appBarLayoutType: AppBarLayoutType
|
|
||||||
get() = AppBarLayoutType.EMPTY
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TAG = "LockedController"
|
|
||||||
private const val REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewBound(view: View) {
|
|
||||||
super.onViewBound(view)
|
|
||||||
sharedApplication!!.componentApplication.inject(this)
|
|
||||||
binding?.unlockContainer?.setOnClickListener {
|
|
||||||
unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttach(view: View) {
|
|
||||||
super.onAttach(view)
|
|
||||||
Log.d(TAG, "onAttach")
|
|
||||||
if (activity != null && resources != null) {
|
|
||||||
DisplayUtils.applyColorToStatusBar(
|
|
||||||
activity,
|
|
||||||
ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
|
|
||||||
)
|
|
||||||
DisplayUtils.applyColorToNavigationBar(
|
|
||||||
activity!!.window,
|
|
||||||
ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
checkIfWeAreSecure()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetach(view: View) {
|
|
||||||
super.onDetach(view)
|
|
||||||
Log.d(TAG, "onDetach")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unlock() {
|
|
||||||
checkIfWeAreSecure()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showBiometricDialog() {
|
|
||||||
val context: Context? = activity
|
|
||||||
if (context != null) {
|
|
||||||
val promptInfo = PromptInfo.Builder()
|
|
||||||
.setTitle(
|
|
||||||
String.format(
|
|
||||||
context.getString(R.string.nc_biometric_unlock),
|
|
||||||
context.getString(R.string.nc_app_product_name)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setNegativeButtonText(context.getString(R.string.nc_cancel))
|
|
||||||
.build()
|
|
||||||
val executor: Executor = Executors.newSingleThreadExecutor()
|
|
||||||
val biometricPrompt = BiometricPrompt(
|
|
||||||
(context as FragmentActivity?)!!,
|
|
||||||
executor,
|
|
||||||
object : BiometricPrompt.AuthenticationCallback() {
|
|
||||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
|
||||||
super.onAuthenticationSucceeded(result)
|
|
||||||
Log.d(TAG, "Fingerprint recognised successfully")
|
|
||||||
Handler(Looper.getMainLooper()).post { router.popCurrentController() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationFailed() {
|
|
||||||
super.onAuthenticationFailed()
|
|
||||||
Log.d(TAG, "Fingerprint not recognised")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
|
||||||
super.onAuthenticationError(errorCode, errString)
|
|
||||||
showAuthenticationScreen()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val cryptoObject = SecurityUtils.getCryptoObject()
|
|
||||||
if (cryptoObject != null) {
|
|
||||||
biometricPrompt.authenticate(promptInfo, cryptoObject)
|
|
||||||
} else {
|
|
||||||
biometricPrompt.authenticate(promptInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkIfWeAreSecure() {
|
|
||||||
val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
|
||||||
if (keyguardManager?.isKeyguardSecure == true && appPreferences.isScreenLocked) {
|
|
||||||
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
|
|
||||||
Log.d(TAG, "showBiometricDialog because 'we are NOT authenticated'...")
|
|
||||||
showBiometricDialog()
|
|
||||||
} else {
|
|
||||||
Log.d(
|
|
||||||
TAG,
|
|
||||||
"popCurrentController because 'we are authenticated'. backstacksize= " +
|
|
||||||
router.backstack.size
|
|
||||||
)
|
|
||||||
router.popToRoot()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showAuthenticationScreen() {
|
|
||||||
Log.d(TAG, "showAuthenticationScreen")
|
|
||||||
val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
|
||||||
val intent = keyguardManager?.createConfirmDeviceCredentialIntent(null, null)
|
|
||||||
if (intent != null) {
|
|
||||||
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
if (
|
|
||||||
SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)
|
|
||||||
) {
|
|
||||||
Log.d(TAG, "All went well, dismiss locked controller")
|
|
||||||
router.popCurrentController()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Authorization failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
153
app/src/main/java/com/nextcloud/talk/lock/LockedActivity.kt
Normal file
153
app/src/main/java/com/nextcloud/talk/lock/LockedActivity.kt
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* @author Andy Scherzinger
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.lock
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.KeyguardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.biometric.BiometricPrompt
|
||||||
|
import autodagger.AutoInjector
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
|
import com.nextcloud.talk.databinding.ActivityLockedBinding
|
||||||
|
import com.nextcloud.talk.utils.SecurityUtils
|
||||||
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
|
class LockedActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var context: Context
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appPreferences: AppPreferences
|
||||||
|
|
||||||
|
private lateinit var binding: ActivityLockedBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||||
|
|
||||||
|
binding = ActivityLockedBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
binding.unlockContainer.setOnClickListener {
|
||||||
|
checkIfWeAreSecure()
|
||||||
|
}
|
||||||
|
checkIfWeAreSecure()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkIfWeAreSecure() {
|
||||||
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
||||||
|
if (keyguardManager?.isKeyguardSecure == true && appPreferences.isScreenLocked) {
|
||||||
|
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
|
||||||
|
Log.d(TAG, "showBiometricDialog because 'we are NOT authenticated'...")
|
||||||
|
showBiometricDialog()
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showBiometricDialog() {
|
||||||
|
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||||
|
.setTitle(
|
||||||
|
String.format(
|
||||||
|
context.getString(R.string.nc_biometric_unlock),
|
||||||
|
context.getString(R.string.nc_app_product_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setNegativeButtonText(context.getString(R.string.nc_cancel))
|
||||||
|
.build()
|
||||||
|
val executor: Executor = Executors.newSingleThreadExecutor()
|
||||||
|
val biometricPrompt = BiometricPrompt(
|
||||||
|
this,
|
||||||
|
executor,
|
||||||
|
object : BiometricPrompt.AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
|
super.onAuthenticationSucceeded(result)
|
||||||
|
Log.d(TAG, "Fingerprint recognised successfully")
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
super.onAuthenticationFailed()
|
||||||
|
Log.d(TAG, "Fingerprint not recognised")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
super.onAuthenticationError(errorCode, errString)
|
||||||
|
showAuthenticationScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val cryptoObject = SecurityUtils.getCryptoObject()
|
||||||
|
if (cryptoObject != null) {
|
||||||
|
biometricPrompt.authenticate(promptInfo, cryptoObject)
|
||||||
|
} else {
|
||||||
|
biometricPrompt.authenticate(promptInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showAuthenticationScreen() {
|
||||||
|
Log.d(TAG, "showAuthenticationScreen")
|
||||||
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
||||||
|
val intent = keyguardManager?.createConfirmDeviceCredentialIntent(null, null)
|
||||||
|
if (intent != null) {
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
if (
|
||||||
|
SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)
|
||||||
|
) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Authorization failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = LockedActivity::class.java.simpleName
|
||||||
|
private const val REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:background="@color/colorPrimary"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user