ma1 pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits:
-
cd556e14
by hackademix at 2024-08-02T22:31:10+02:00
-
c60897e8
by hackademix at 2024-08-02T22:57:38+02:00
-
1e885468
by hackademix at 2024-08-02T23:25:03+02:00
-
233d8217
by hackademix at 2024-08-04T17:32:36+02:00
7 changed files:
- android-components/.buildconfig.yml
- android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt
- android-components/components/feature/sitepermissions/build.gradle
- android-components/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsDialogFragment.kt
- android-components/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsDialogFragmentTest.kt
- android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/dialog/PromptAbuserDetector.kt → android-components/components/support/utils/src/main/java/mozilla/components/support/ktx/util/PromptAbuserDetector.kt
- focus-android/app/src/androidTest/java/org/mozilla/focus/activity/SitePermissionsTest.kt
Changes:
... | ... | @@ -1150,7 +1150,6 @@ projects: |
1150 | 1150 | - concept-tabstray
|
1151 | 1151 | - concept-toolbar
|
1152 | 1152 | - feature-session
|
1153 | - - feature-prompts
|
|
1154 | 1153 | - feature-tabs
|
1155 | 1154 | - lib-publicsuffixlist
|
1156 | 1155 | - lib-state
|
... | ... | @@ -61,7 +61,6 @@ import mozilla.components.feature.prompts.dialog.ChoiceDialogFragment.Companion. |
61 | 61 | import mozilla.components.feature.prompts.dialog.ColorPickerDialogFragment
|
62 | 62 | import mozilla.components.feature.prompts.dialog.ConfirmDialogFragment
|
63 | 63 | import mozilla.components.feature.prompts.dialog.MultiButtonDialogFragment
|
64 | -import mozilla.components.feature.prompts.dialog.PromptAbuserDetector
|
|
65 | 64 | import mozilla.components.feature.prompts.dialog.PromptDialogFragment
|
66 | 65 | import mozilla.components.feature.prompts.dialog.Prompter
|
67 | 66 | import mozilla.components.feature.prompts.dialog.SaveLoginDialogFragment
|
... | ... | @@ -91,6 +90,7 @@ import mozilla.components.support.base.feature.UserInteractionHandler |
91 | 90 | import mozilla.components.support.base.log.logger.Logger
|
92 | 91 | import mozilla.components.support.ktx.kotlin.ifNullOrEmpty
|
93 | 92 | import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
|
93 | +import mozilla.components.support.ktx.util.PromptAbuserDetector
|
|
94 | 94 | import java.lang.ref.WeakReference
|
95 | 95 | import java.security.InvalidParameterException
|
96 | 96 | import java.util.Collections
|
... | ... | @@ -467,36 +467,51 @@ class PromptFeature private constructor( |
467 | 467 | internal fun onPromptRequested(session: SessionState) {
|
468 | 468 | // Some requests are handle with intents
|
469 | 469 | session.content.promptRequests.lastOrNull()?.let { promptRequest ->
|
470 | - store.state.findTabOrCustomTabOrSelectedTab(customTabId)?.let {
|
|
471 | - promptRequest.executeIfWindowedPrompt { exitFullscreenUsecase(it.id) }
|
|
470 | + if (session.content.permissionRequestsList.isNotEmpty()) {
|
|
471 | + onCancel(session.id, promptRequest.uid)
|
|
472 | + } else {
|
|
473 | + processPromptRequest(promptRequest, session)
|
|
472 | 474 | }
|
475 | + }
|
|
476 | + }
|
|
473 | 477 | |
474 | - when (promptRequest) {
|
|
475 | - is File -> {
|
|
476 | - emitPromptDisplayedFact(promptName = "FilePrompt")
|
|
477 | - filePicker.handleFileRequest(promptRequest)
|
|
478 | - }
|
|
479 | - is Share -> handleShareRequest(promptRequest, session)
|
|
480 | - is SelectCreditCard -> {
|
|
481 | - emitSuccessfulCreditCardAutofillFormDetectedFact()
|
|
482 | - if (isCreditCardAutofillEnabled() && promptRequest.creditCards.isNotEmpty()) {
|
|
483 | - creditCardPicker?.handleSelectCreditCardRequest(promptRequest)
|
|
484 | - }
|
|
478 | + @Suppress("NestedBlockDepth")
|
|
479 | + private fun processPromptRequest(
|
|
480 | + promptRequest: PromptRequest,
|
|
481 | + session: SessionState,
|
|
482 | + ) {
|
|
483 | + store.state.findTabOrCustomTabOrSelectedTab(customTabId)?.let {
|
|
484 | + promptRequest.executeIfWindowedPrompt { exitFullscreenUsecase(it.id) }
|
|
485 | + }
|
|
486 | + |
|
487 | + when (promptRequest) {
|
|
488 | + is File -> {
|
|
489 | + emitPromptDisplayedFact(promptName = "FilePrompt")
|
|
490 | + filePicker.handleFileRequest(promptRequest)
|
|
491 | + }
|
|
492 | + |
|
493 | + is Share -> handleShareRequest(promptRequest, session)
|
|
494 | + is SelectCreditCard -> {
|
|
495 | + emitSuccessfulCreditCardAutofillFormDetectedFact()
|
|
496 | + if (isCreditCardAutofillEnabled() && promptRequest.creditCards.isNotEmpty()) {
|
|
497 | + creditCardPicker?.handleSelectCreditCardRequest(promptRequest)
|
|
485 | 498 | }
|
486 | - is SelectLoginPrompt -> {
|
|
487 | - emitPromptDisplayedFact(promptName = "SelectLoginPrompt")
|
|
488 | - if (promptRequest.logins.isNotEmpty()) {
|
|
489 | - loginPicker?.handleSelectLoginRequest(promptRequest)
|
|
490 | - }
|
|
499 | + }
|
|
500 | + |
|
501 | + is SelectLoginPrompt -> {
|
|
502 | + emitPromptDisplayedFact(promptName = "SelectLoginPrompt")
|
|
503 | + if (promptRequest.logins.isNotEmpty()) {
|
|
504 | + loginPicker?.handleSelectLoginRequest(promptRequest)
|
|
491 | 505 | }
|
492 | - is SelectAddress -> {
|
|
493 | - emitSuccessfulAddressAutofillFormDetectedFact()
|
|
494 | - if (isAddressAutofillEnabled() && promptRequest.addresses.isNotEmpty()) {
|
|
495 | - addressPicker?.handleSelectAddressRequest(promptRequest)
|
|
496 | - }
|
|
506 | + }
|
|
507 | + is SelectAddress -> {
|
|
508 | + emitSuccessfulAddressAutofillFormDetectedFact()
|
|
509 | + if (isAddressAutofillEnabled() && promptRequest.addresses.isNotEmpty()) {
|
|
510 | + addressPicker?.handleSelectAddressRequest(promptRequest)
|
|
497 | 511 | }
|
498 | - else -> handleDialogsRequest(promptRequest, session)
|
|
499 | 512 | }
|
513 | + |
|
514 | + else -> handleDialogsRequest(promptRequest, session)
|
|
500 | 515 | }
|
501 | 516 | }
|
502 | 517 |
... | ... | @@ -58,8 +58,8 @@ dependencies { |
58 | 58 | implementation project(':concept-engine')
|
59 | 59 | implementation project(':ui-icons')
|
60 | 60 | implementation project(':support-ktx')
|
61 | - implementation project(':feature-prompts')
|
|
62 | 61 | implementation project(':feature-tabs')
|
62 | + implementation project(':support-utils')
|
|
63 | 63 | |
64 | 64 | implementation ComponentsDependencies.kotlin_coroutines
|
65 | 65 |
... | ... | @@ -23,7 +23,7 @@ import android.widget.TextView |
23 | 23 | import androidx.annotation.VisibleForTesting
|
24 | 24 | import androidx.appcompat.app.AppCompatDialogFragment
|
25 | 25 | import androidx.core.content.ContextCompat
|
26 | -import mozilla.components.feature.prompts.dialog.PromptAbuserDetector
|
|
26 | +import mozilla.components.support.ktx.util.PromptAbuserDetector
|
|
27 | 27 | |
28 | 28 | internal const val KEY_SESSION_ID = "KEY_SESSION_ID"
|
29 | 29 | internal const val KEY_TITLE = "KEY_TITLE"
|
... | ... | @@ -19,6 +19,7 @@ import mozilla.components.support.test.robolectric.testContext |
19 | 19 | import org.junit.Assert.assertEquals
|
20 | 20 | import org.junit.Assert.assertFalse
|
21 | 21 | import org.junit.Assert.assertTrue
|
22 | +import org.junit.Ignore
|
|
22 | 23 | import org.junit.Test
|
23 | 24 | import org.junit.runner.RunWith
|
24 | 25 | import org.mockito.Mockito.doNothing
|
... | ... | @@ -233,6 +234,7 @@ class SitePermissionsDialogFragmentTest { |
233 | 234 | }
|
234 | 235 | |
235 | 236 | @Test
|
237 | + @Ignore("https://bugzilla.mozilla.org/show_bug.cgi?id=1903828")
|
|
236 | 238 | fun `clicking on positive button notifies the feature (temporary)`() {
|
237 | 239 | val mockFeature: SitePermissionsFeature = mock()
|
238 | 240 | val fragment = spy(
|
... | ... | @@ -261,6 +263,7 @@ class SitePermissionsDialogFragmentTest { |
261 | 263 | }
|
262 | 264 | |
263 | 265 | @Test
|
266 | + @Ignore("https://bugzilla.mozilla.org/show_bug.cgi?id=1903828")
|
|
264 | 267 | fun `dismissing the dialog notifies the feature`() {
|
265 | 268 | val mockFeature: SitePermissionsFeature = mock()
|
266 | 269 | val fragment = spy(
|
... | ... | @@ -360,6 +363,7 @@ class SitePermissionsDialogFragmentTest { |
360 | 363 | }
|
361 | 364 | |
362 | 365 | @Test
|
366 | + @Ignore("https://bugzilla.mozilla.org/show_bug.cgi?id=1903828")
|
|
363 | 367 | fun `clicking on positive button notifies the feature (permanent)`() {
|
364 | 368 | val mockFeature: SitePermissionsFeature = mock()
|
365 | 369 | val fragment = spy(
|
... | ... | @@ -389,6 +393,7 @@ class SitePermissionsDialogFragmentTest { |
389 | 393 | }
|
390 | 394 | |
391 | 395 | @Test
|
396 | + @Ignore("https://bugzilla.mozilla.org/show_bug.cgi?id=1903828")
|
|
392 | 397 | fun `clicking on negative button notifies the feature (permanent)`() {
|
393 | 398 | val mockFeature: SitePermissionsFeature = mock()
|
394 | 399 | val fragment = spy(
|
... | ... | @@ -2,25 +2,38 @@ |
2 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this
|
3 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
4 | 4 | |
5 | -package mozilla.components.feature.prompts.dialog
|
|
5 | +package mozilla.components.support.ktx.util
|
|
6 | 6 | |
7 | +import androidx.annotation.VisibleForTesting
|
|
7 | 8 | import java.util.Date
|
8 | 9 | |
9 | 10 | /**
|
10 | 11 | * Helper class to identify if a website has shown many dialogs.
|
12 | + * @param maxSuccessiveDialogSecondsLimit Maximum time required
|
|
13 | + * between dialogs in seconds before not showing more dialog.
|
|
11 | 14 | */
|
12 | 15 | class PromptAbuserDetector(private val maxSuccessiveDialogSecondsLimit: Int = MAX_SUCCESSIVE_DIALOG_SECONDS_LIMIT) {
|
13 | 16 | |
14 | - internal var jsAlertCount = 0
|
|
15 | - internal var lastDialogShownAt = Date()
|
|
17 | + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
18 | + var jsAlertCount = 0
|
|
19 | + |
|
20 | + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
21 | + var lastDialogShownAt = Date()
|
|
22 | + |
|
16 | 23 | var shouldShowMoreDialogs = true
|
17 | 24 | private set
|
18 | 25 | |
26 | + /**
|
|
27 | + * Updates internal state for alerts counts.
|
|
28 | + */
|
|
19 | 29 | fun resetJSAlertAbuseState() {
|
20 | 30 | jsAlertCount = 0
|
21 | 31 | shouldShowMoreDialogs = true
|
22 | 32 | }
|
23 | 33 | |
34 | + /**
|
|
35 | + * Updates internal state for last shown and count of dialogs.
|
|
36 | + */
|
|
24 | 37 | fun updateJSDialogAbusedState() {
|
25 | 38 | if (!areDialogsAbusedByTime()) {
|
26 | 39 | jsAlertCount = 0
|
... | ... | @@ -29,25 +42,35 @@ class PromptAbuserDetector(private val maxSuccessiveDialogSecondsLimit: Int = MA |
29 | 42 | lastDialogShownAt = Date()
|
30 | 43 | }
|
31 | 44 | |
45 | + /**
|
|
46 | + * Indicates whether or not user wants to see more dialogs.
|
|
47 | + */
|
|
32 | 48 | fun userWantsMoreDialogs(checkBox: Boolean) {
|
33 | 49 | shouldShowMoreDialogs = checkBox
|
34 | 50 | }
|
35 | 51 | |
52 | + /**
|
|
53 | + * Indicates whether dialogs are being abused or not.
|
|
54 | + */
|
|
36 | 55 | fun areDialogsBeingAbused(): Boolean {
|
37 | 56 | return areDialogsAbusedByTime() || areDialogsAbusedByCount()
|
38 | 57 | }
|
39 | 58 | |
40 | - internal fun areDialogsAbusedByTime(): Boolean {
|
|
59 | + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
60 | + @Suppress("UndocumentedPublicFunction") // this is visible only for tests
|
|
61 | + fun now() = Date()
|
|
62 | + |
|
63 | + private fun areDialogsAbusedByTime(): Boolean {
|
|
41 | 64 | return if (jsAlertCount == 0) {
|
42 | 65 | false
|
43 | 66 | } else {
|
44 | - val now = Date()
|
|
67 | + val now = now()
|
|
45 | 68 | val diffInSeconds = (now.time - lastDialogShownAt.time) / SECOND_MS
|
46 | 69 | diffInSeconds < maxSuccessiveDialogSecondsLimit
|
47 | 70 | }
|
48 | 71 | }
|
49 | 72 | |
50 | - internal fun areDialogsAbusedByCount(): Boolean {
|
|
73 | + private fun areDialogsAbusedByCount(): Boolean {
|
|
51 | 74 | return jsAlertCount > MAX_SUCCESSIVE_DIALOG_COUNT
|
52 | 75 | }
|
53 | 76 |
... | ... | @@ -229,6 +229,7 @@ class SitePermissionsTest { |
229 | 229 | |
230 | 230 | @SmokeTest
|
231 | 231 | @Test
|
232 | + @Ignore
|
|
232 | 233 | fun testLocationSharingAllowed() {
|
233 | 234 | mockLocationUpdatesRule.setMockLocation()
|
234 | 235 | |
... | ... | @@ -244,6 +245,7 @@ class SitePermissionsTest { |
244 | 245 | |
245 | 246 | @SmokeTest
|
246 | 247 | @Test
|
248 | + @Ignore
|
|
247 | 249 | fun allowCameraPermissionsTest() {
|
248 | 250 | Assume.assumeTrue(cameraManager.cameraIdList.isNotEmpty())
|
249 | 251 | searchScreen {
|