Basic replacement of the Pin screen from BaseActivity.java to PinLockManager.kt

The Pin screen is now shown when it's supposed to be shown and the back
button is inhibited, still need to migrate measures for screen in Recent
 apps and flashing of the previous activity

MAILAND-2542
This commit is contained in:
Davide Farella 2022-01-14 15:32:02 +01:00
parent dedae75aad
commit 2abb66a4d5
7 changed files with 198 additions and 15 deletions

View File

@ -86,6 +86,10 @@
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
<meta-data
android:name="ch.protonmail.android.pinlock.presentation.PinLockManagerInitializer"
android:value="androidx.startup" />
</provider>
<provider

View File

@ -18,7 +18,6 @@
*/
package ch.protonmail.android.activities;
import static ch.protonmail.android.settings.pin.ValidatePinActivityKt.EXTRA_FRAGMENT_TITLE;
import static ch.protonmail.android.settings.pin.ValidatePinActivityKt.EXTRA_PIN_VALID;
import static ch.protonmail.android.worker.FetchUserWorkerKt.FETCH_USER_INFO_WORKER_NAME;
import static ch.protonmail.android.worker.FetchUserWorkerKt.FETCH_USER_INFO_WORKER_RESULT;
@ -262,7 +261,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
if (shouldLock && (secureContent() || user != null && user.isPreventTakingScreenshots())) {
enableScreenshotProtector();
// enableScreenshotProtector();
}
app.setAppInBackground(false);
networkConfigurator.setNetworkConfiguratorCallback(this);
@ -326,9 +325,8 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
}
if (shouldLock) {
Intent validatePinIntent = new Intent(this, ValidatePinActivity.class);
validatePinIntent.putExtra(EXTRA_FRAGMENT_TITLE, R.string.settings_enter_pin_code_title);
Intent pinIntent = AppUtil.decorInAppIntent(validatePinIntent);
startActivityForResult(pinIntent, REQUEST_CODE_VALIDATE_PIN);
// startActivityForResult(pinIntent, REQUEST_CODE_VALIDATE_PIN);
} else {
this.shouldLock = false;

View File

@ -55,7 +55,6 @@ import ch.protonmail.android.labels.domain.model.LabelType
import ch.protonmail.android.labels.presentation.ui.EXTRA_MANAGE_FOLDERS
import ch.protonmail.android.labels.presentation.ui.LabelsManagerActivity
import ch.protonmail.android.servers.notification.EXTRA_USER_ID
import ch.protonmail.android.settings.pin.EXTRA_FRAGMENT_TITLE
import ch.protonmail.android.settings.pin.ValidatePinActivity
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.UiUtil
@ -451,7 +450,6 @@ internal abstract class NavigationActivity : BaseActivity() {
if (user != null && user.isUsePin && userManager.getMailboxPin() != null) {
user.setManuallyLocked(true)
val pinIntent = AppUtil.decorInAppIntent(Intent(this, ValidatePinActivity::class.java))
pinIntent.putExtra(EXTRA_FRAGMENT_TITLE, R.string.settings_enter_pin_code_title)
startActivityForResult(pinIntent, REQUEST_CODE_VALIDATE_PIN)
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.pinlock.presentation
import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import ch.protonmail.android.pinlock.domain.usecase.GetPinLockTimer
import ch.protonmail.android.pinlock.domain.usecase.IsPinLockEnabled
import ch.protonmail.android.settings.pin.ValidatePinActivity
import ch.protonmail.android.utils.EmptyActivityLifecycleCallbacks
import ch.protonmail.android.utils.extensions.app
import kotlinx.coroutines.runBlocking
import me.proton.core.presentation.app.AppLifecycleProvider
import timber.log.Timber
import java.lang.System.currentTimeMillis
import java.util.concurrent.TimeUnit.MILLISECONDS
import kotlin.time.toDuration
class PinLockManager(
private val context: Context,
private val isPinLockEnabled: IsPinLockEnabled,
private val getPinLockTimer: GetPinLockTimer
) : LifecycleObserver {
private var appState: AppLifecycleProvider.State = AppLifecycleProvider.State.Background
private var lastForegroundTime: Long = 0
init {
context.app.registerActivityLifecycleCallbacks(object : EmptyActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
super.onActivityStarted(activity)
Timber.v("Activity started")
@Suppress("BlockingMethodInNonBlockingContext") // This needs to be run blocking, in order to
// prevent the last activity to be displayed
runBlocking {
if (appState == AppLifecycleProvider.State.Background && shouldLock()) {
launchPinLockActivity(activity)
}
}
}
})
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
@Suppress("unused") // Called by LifecycleObserver
fun onEnterForeground() {
Timber.v("App Foreground")
appState = AppLifecycleProvider.State.Foreground
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
@Suppress("unused") // Called by LifecycleObserver
fun onEnterBackground() {
Timber.v("App Background")
appState = AppLifecycleProvider.State.Background
lastForegroundTime = currentTimeMillis()
}
private suspend fun shouldLock(): Boolean {
return if (isPinLockEnabled()) {
val diff = (currentTimeMillis() - lastForegroundTime).toDuration(MILLISECONDS)
return diff > getPinLockTimer()
} else {
false
}
}
private fun launchPinLockActivity(callingActivity: Activity) {
val intent = Intent(context, ValidatePinActivity::class.java)
callingActivity.startActivity(intent)
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.pinlock.presentation
import android.content.Context
import androidx.startup.Initializer
import ch.protonmail.android.pinlock.domain.usecase.GetPinLockTimer
import ch.protonmail.android.pinlock.domain.usecase.IsPinLockEnabled
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
class PinLockManagerInitializer : Initializer<PinLockManager> {
override fun create(context: Context): PinLockManager {
val entryPoint = EntryPointAccessors.fromApplication(context, PinLockManagerEntryPoint::class.java)
return PinLockManager(
context,
isPinLockEnabled = entryPoint.isPinLockEnabled(),
getPinLockTimer = entryPoint.getPinLockTimer()
)
}
override fun dependencies() = emptyList<Class<out Initializer<*>>>()
@EntryPoint
@InstallIn(SingletonComponent::class)
interface PinLockManagerEntryPoint {
fun isPinLockEnabled(): IsPinLockEnabled
fun getPinLockTimer(): GetPinLockTimer
}
}

View File

@ -32,7 +32,6 @@ import ch.protonmail.android.events.FetchDraftDetailEvent
import ch.protonmail.android.events.FetchMessageDetailEvent
import ch.protonmail.android.events.PostImportAttachmentEvent
import ch.protonmail.android.settings.pin.viewmodel.PinFragmentViewModel
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.extensions.showToast
import ch.protonmail.android.utils.ui.dialogs.DialogUtils
import ch.protonmail.android.views.ISecurePINListener
@ -41,7 +40,6 @@ import java.util.concurrent.Executors
// region constants
const val EXTRA_PIN_VALID = "extra_pin_valid"
const val EXTRA_FRAGMENT_TITLE = "extra_title"
const val EXTRA_ATTACHMENT_IMPORT_EVENT = "extra_attachment_import_event"
const val EXTRA_MESSAGE_DETAIL_EVENT = "extra_message_details_event"
const val EXTRA_DRAFT_DETAILS_EVENT = "extra_draft_details_event"
@ -68,11 +66,12 @@ class ValidatePinActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
if (savedInstanceState != null) {
return
}
val user = mUserManager.requireCurrentLegacyUser()
val titleRes = intent.getIntExtra(EXTRA_FRAGMENT_TITLE, 0)
val titleRes = R.string.settings_enter_pin_code_title
val validatePinFragment =
PinFragment.newInstance(titleRes, PinAction.VALIDATE, null, useFingerprint = user.isUseFingerprint)
supportFragmentManager
@ -199,12 +198,7 @@ class ValidatePinActivity :
}
}
override fun onBackPressed() {
if (!AppUtil.isLockTaskModeRunning(this)) {
setResult(Activity.RESULT_CANCELED, Intent().apply { putExtra(EXTRA_PIN_VALID, false) })
finish()
}
}
override fun onBackPressed() {}
private fun buildIntent(): Intent {
return Intent().apply {

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail 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.
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.utils
import android.app.Activity
import android.app.Application
import android.os.Bundle
/**
* Interface that implements [Application.ActivityLifecycleCallbacks] with empty methods, use this to avoid to implement
* every methods of the Callbacks
*/
interface EmptyActivityLifecycleCallbacks : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
}