|
|
|
@ -4,11 +4,14 @@
|
|
|
|
|
|
|
|
|
|
package org.mozilla.fenix.browser
|
|
|
|
|
|
|
|
|
|
import android.app.KeyguardManager
|
|
|
|
|
import android.content.Context
|
|
|
|
|
import android.content.DialogInterface
|
|
|
|
|
import android.content.Intent
|
|
|
|
|
import android.content.res.Configuration
|
|
|
|
|
import android.os.Build
|
|
|
|
|
import android.os.Bundle
|
|
|
|
|
import android.provider.Settings
|
|
|
|
|
import android.view.Gravity
|
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
|
import android.view.View
|
|
|
|
@ -16,7 +19,9 @@ import android.view.ViewGroup
|
|
|
|
|
import android.view.accessibility.AccessibilityManager
|
|
|
|
|
import androidx.annotation.CallSuper
|
|
|
|
|
import androidx.annotation.VisibleForTesting
|
|
|
|
|
import androidx.appcompat.app.AlertDialog
|
|
|
|
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
|
|
|
import androidx.core.content.getSystemService
|
|
|
|
|
import androidx.core.net.toUri
|
|
|
|
|
import androidx.core.view.isVisible
|
|
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
@ -65,6 +70,7 @@ import mozilla.components.feature.intent.ext.EXTRA_SESSION_ID
|
|
|
|
|
import mozilla.components.feature.media.fullscreen.MediaSessionFullscreenFeature
|
|
|
|
|
import mozilla.components.feature.privatemode.feature.SecureWindowFeature
|
|
|
|
|
import mozilla.components.feature.prompts.PromptFeature
|
|
|
|
|
import mozilla.components.feature.prompts.PromptFeature.Companion.PIN_REQUEST
|
|
|
|
|
import mozilla.components.feature.prompts.share.ShareDelegate
|
|
|
|
|
import mozilla.components.feature.readerview.ReaderViewFeature
|
|
|
|
|
import mozilla.components.feature.search.SearchFeature
|
|
|
|
@ -132,6 +138,8 @@ import org.mozilla.fenix.ext.navigateBlockingForAsyncNavGraph
|
|
|
|
|
import mozilla.components.support.ktx.android.view.enterToImmersiveMode
|
|
|
|
|
import org.mozilla.fenix.GleanMetrics.PerfStartup
|
|
|
|
|
import org.mozilla.fenix.ext.measureNoInline
|
|
|
|
|
import org.mozilla.fenix.ext.secure
|
|
|
|
|
import org.mozilla.fenix.settings.biometric.BiometricPromptFeature
|
|
|
|
|
import mozilla.components.feature.session.behavior.ToolbarPosition as MozacToolbarPosition
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -180,6 +188,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|
|
|
|
ViewBoundFeatureWrapper<MediaSessionFullscreenFeature>()
|
|
|
|
|
private val searchFeature = ViewBoundFeatureWrapper<SearchFeature>()
|
|
|
|
|
private val webAuthnFeature = ViewBoundFeatureWrapper<WebAuthnFeature>()
|
|
|
|
|
private val biometricPromptFeature = ViewBoundFeatureWrapper<BiometricPromptFeature>()
|
|
|
|
|
private var pipFeature: PictureInPictureFeature? = null
|
|
|
|
|
|
|
|
|
|
var customTabSessionId: String? = null
|
|
|
|
@ -533,6 +542,21 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|
|
|
|
view = view
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
biometricPromptFeature.set(
|
|
|
|
|
feature = BiometricPromptFeature(
|
|
|
|
|
context = context,
|
|
|
|
|
fragment = this,
|
|
|
|
|
onAuthFailure = {
|
|
|
|
|
promptsFeature.get()?.onBiometricResult(isAuthenticated = false)
|
|
|
|
|
},
|
|
|
|
|
onAuthSuccess = {
|
|
|
|
|
promptsFeature.get()?.onBiometricResult(isAuthenticated = true)
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
owner = this,
|
|
|
|
|
view = view
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
promptsFeature.set(
|
|
|
|
|
feature = PromptFeature(
|
|
|
|
|
activity = activity,
|
|
|
|
@ -580,6 +604,9 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|
|
|
|
val directions =
|
|
|
|
|
NavGraphDirections.actionGlobalCreditCardsSettingFragment()
|
|
|
|
|
findNavController().navigateBlockingForAsyncNavGraph(directions)
|
|
|
|
|
},
|
|
|
|
|
onSelectCreditCard = {
|
|
|
|
|
showBiometricPrompt(context)
|
|
|
|
|
}
|
|
|
|
|
),
|
|
|
|
|
owner = this,
|
|
|
|
@ -731,6 +758,66 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
|
|
|
|
initializeEngineView(toolbarHeight)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shows a biometric prompt and fallback to prompting for the password.
|
|
|
|
|
*/
|
|
|
|
|
private fun showBiometricPrompt(context: Context) {
|
|
|
|
|
if (BiometricPromptFeature.canUseFeature(context)) {
|
|
|
|
|
biometricPromptFeature.get()
|
|
|
|
|
?.requestAuthentication(getString(R.string.credit_cards_biometric_prompt_unlock_message))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fallback to prompting for password with the KeyguardManager
|
|
|
|
|
val manager = context.getSystemService<KeyguardManager>()
|
|
|
|
|
if (manager?.isKeyguardSecure == true) {
|
|
|
|
|
showPinVerification(manager)
|
|
|
|
|
} else {
|
|
|
|
|
// Warn that the device has not been secured
|
|
|
|
|
if (context.settings().shouldShowSecurityPinWarning) {
|
|
|
|
|
showPinDialogWarning(context)
|
|
|
|
|
} else {
|
|
|
|
|
promptsFeature.get()?.onBiometricResult(isAuthenticated = true)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shows a pin request prompt. This is only used when BiometricPrompt is unavailable.
|
|
|
|
|
*/
|
|
|
|
|
@Suppress("Deprecation")
|
|
|
|
|
private fun showPinVerification(manager: KeyguardManager) {
|
|
|
|
|
val intent = manager.createConfirmDeviceCredentialIntent(
|
|
|
|
|
getString(R.string.credit_cards_biometric_prompt_message_pin),
|
|
|
|
|
getString(R.string.credit_cards_biometric_prompt_unlock_message)
|
|
|
|
|
)
|
|
|
|
|
requireActivity().startActivityForResult(intent, PIN_REQUEST)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shows a dialog warning about setting up a device lock PIN.
|
|
|
|
|
*/
|
|
|
|
|
private fun showPinDialogWarning(context: Context) {
|
|
|
|
|
AlertDialog.Builder(context).apply {
|
|
|
|
|
setTitle(getString(R.string.credit_cards_warning_dialog_title))
|
|
|
|
|
setMessage(getString(R.string.credit_cards_warning_dialog_message))
|
|
|
|
|
|
|
|
|
|
setNegativeButton(getString(R.string.credit_cards_warning_dialog_later)) { _: DialogInterface, _ ->
|
|
|
|
|
promptsFeature.get()?.onBiometricResult(isAuthenticated = false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setPositiveButton(getString(R.string.credit_cards_warning_dialog_set_up_now)) { it: DialogInterface, _ ->
|
|
|
|
|
it.dismiss()
|
|
|
|
|
promptsFeature.get()?.onBiometricResult(isAuthenticated = false)
|
|
|
|
|
startActivity(Intent(Settings.ACTION_SECURITY_SETTINGS))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create()
|
|
|
|
|
}.show().secure(activity)
|
|
|
|
|
|
|
|
|
|
context.settings().incrementSecureWarningCount()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@VisibleForTesting
|
|
|
|
|
internal fun expandToolbarOnNavigation(store: BrowserStore) {
|
|
|
|
|
consumeFlow(store) { flow ->
|
|
|
|
|