diff --git a/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java b/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java deleted file mode 100644 index c34c2cbe3..000000000 --- a/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017-2018 Mario Danic - * - * 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 . - */ - -package com.nextcloud.talk.controllers; - -import android.app.Activity; -import android.app.KeyguardManager; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.nextcloud.talk.R; -import com.nextcloud.talk.application.NextcloudTalkApplication; -import com.nextcloud.talk.controllers.base.BaseController; -import com.nextcloud.talk.utils.DisplayUtils; -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; - -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import androidx.biometric.BiometricPrompt; -import androidx.core.content.res.ResourcesCompat; -import androidx.fragment.app.FragmentActivity; -import autodagger.AutoInjector; -import butterknife.OnClick; - -@AutoInjector(NextcloudTalkApplication.class) -public class LockedController extends BaseController { - public static final String TAG = "LockedController"; - private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112; - - @Inject - AppPreferences appPreferences; - - @NonNull - @Override - protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { - return inflater.inflate(R.layout.controller_locked, container, false); - } - - @Override - protected void onViewBound(@NonNull View view) { - super.onViewBound(view); - NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - protected void onAttach(@NonNull View view) { - super.onAttach(view); - if (getActivity() != null && getResources() != null) { - DisplayUtils.applyColorToStatusBar(getActivity(), ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null)); - DisplayUtils.applyColorToNavigationBar(getActivity().getWindow(), ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null)); - } - checkIfWeAreSecure(); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @OnClick(R.id.unlockContainer) - void unlock() { - checkIfWeAreSecure(); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - private void showBiometricDialog() { - Context context = getActivity(); - - if (context != null) { - final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder() - .setTitle(String.format(context.getString(R.string.nc_biometric_unlock), context.getString(R.string.nc_app_name))) - .setNegativeButtonText(context.getString(R.string.nc_cancel)) - .build(); - - Executor executor = Executors.newSingleThreadExecutor(); - - final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) context, executor, - new BiometricPrompt.AuthenticationCallback() { - @Override - public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { - super.onAuthenticationSucceeded(result); - Log.d(TAG, "Fingerprint recognised successfully"); - new Handler(Looper.getMainLooper()).post(() -> getRouter().popCurrentController()); - } - - @Override - public void onAuthenticationFailed() { - super.onAuthenticationFailed(); - Log.d(TAG, "Fingerprint not recognised"); - } - - @Override - public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { - super.onAuthenticationError(errorCode, errString); - showAuthenticationScreen(); - } - } - ); - - BiometricPrompt.CryptoObject cryptoObject = SecurityUtils.getCryptoObject(); - if (cryptoObject != null) { - biometricPrompt.authenticate(promptInfo, cryptoObject); - } else { - biometricPrompt.authenticate(promptInfo); - } - } - } - - @RequiresApi(api = Build.VERSION_CODES.M) - private void checkIfWeAreSecure() { - if (getActivity() != null) { - KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE); - if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) { - if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) { - showBiometricDialog(); - } else { - getRouter().popCurrentController(); - } - } - } - } - - private void showAuthenticationScreen() { - if (getActivity() != null) { - KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE); - Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null, null); - if (intent != null) { - startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS); - } - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) { - if (resultCode == Activity.RESULT_OK) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) { - Log.d(TAG, "All went well, dismiss locked controller"); - getRouter().popCurrentController(); - } - } - } else { - Log.d(TAG, "Authorization failed"); - } - } - } - - public AppBarLayoutType getAppBarLayoutType() { - return AppBarLayoutType.EMPTY; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/controllers/LockedController.kt b/app/src/main/java/com/nextcloud/talk/controllers/LockedController.kt new file mode 100644 index 000000000..109d08436 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/controllers/LockedController.kt @@ -0,0 +1,173 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * @author Andy Scherzinger + * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2017-2018 Mario Danic + * + * 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 . + */ +package com.nextcloud.talk.controllers + +import android.app.Activity +import android.app.KeyguardManager +import android.content.Context +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.util.Log +import android.view.View +import androidx.annotation.RequiresApi +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.NewBaseController +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 : NewBaseController(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) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + binding.unlockContainer.setOnClickListener { + unlock() + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.M) + override fun onAttach(view: View) { + super.onAttach(view) + 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() + } + + @RequiresApi(api = Build.VERSION_CODES.M) + fun unlock() { + checkIfWeAreSecure() + } + + @RequiresApi(api = Build.VERSION_CODES.M) + 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_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) + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private fun checkIfWeAreSecure() { + val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager? + if (keyguardManager?.isKeyguardSecure == true && appPreferences!!.isScreenLocked) { + if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences!!.screenLockTimeout)) { + showBiometricDialog() + } else { + router.popCurrentController() + } + } + } + + private fun 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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences!!.screenLockTimeout)) { + Log.d(TAG, "All went well, dismiss locked controller") + router.popCurrentController() + } + } + } else { + Log.d(TAG, "Authorization failed") + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/controllers/base/NewBaseController.kt b/app/src/main/java/com/nextcloud/talk/controllers/base/NewBaseController.kt index 120e561d8..d7f3fc7e3 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/base/NewBaseController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/base/NewBaseController.kt @@ -251,7 +251,7 @@ abstract class NewBaseController(@LayoutRes var layoutRes: Int, args: Bundle? = } } - val appBarLayoutType: AppBarLayoutType + open val appBarLayoutType: AppBarLayoutType get() = AppBarLayoutType.TOOLBAR val searchHint: String get() = context!!.getString(R.string.appbar_search_in, context!!.getString(R.string.nc_app_name))