From 2a31edccf2bab2c84d8cf274800c11017c720457 Mon Sep 17 00:00:00 2001 From: Mickey Moz <33347735+MickeyMoz@users.noreply.github.com> Date: Wed, 6 Oct 2021 02:59:32 +0200 Subject: [PATCH 001/563] Update Android Components version to 95.0.20211005200555. (#21725) --- buildSrc/src/main/java/AndroidComponents.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 33544e580..d569a3cec 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "94.0.20211005143407" + const val VERSION = "95.0.20211005200555" } From fb732cc953825e0a509b626c8e183b620d7b9772 Mon Sep 17 00:00:00 2001 From: Roger Yang Date: Tue, 5 Oct 2021 19:28:14 -0400 Subject: [PATCH 002/563] Update version.txt to 95.0.0-beta.1 --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index b94447a7f..ec599a191 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -94.0.0-beta.1 +95.0.0-beta.1 From 7e3a2ba89d2ecfb3b4c9c35153d8b81554339ba1 Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Tue, 5 Oct 2021 17:18:11 -0400 Subject: [PATCH 003/563] For #21574: disabled the homescreen onboarding dialog. --- app/src/debug/res/raw/initial_experiments.json | 2 +- app/src/main/java/org/mozilla/fenix/FeatureFlags.kt | 5 +++++ .../home/sessioncontrol/SessionControlController.kt | 11 +++++++---- .../fenix/home/DefaultSessionControlControllerTest.kt | 1 + 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/debug/res/raw/initial_experiments.json b/app/src/debug/res/raw/initial_experiments.json index 6bced9269..3514af8ee 100644 --- a/app/src/debug/res/raw/initial_experiments.json +++ b/app/src/debug/res/raw/initial_experiments.json @@ -12,7 +12,7 @@ "value": { "sections-enabled": { "topSites": true, - "recentExplorations": true, + "recentExplorations": false, "recentlySaved": false, "jumpBackIn": false, "pocket": false diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index 4fc1cb004..165beb782 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -85,4 +85,9 @@ object FeatureFlags { return "en-US" == LocaleManager.getCurrentLocale(context) ?.toLanguageTag() ?: getSystemDefault().toLanguageTag() } + + /** + * Enables showing the homescreen onboarding card. + */ + const val showHomeOnboarding = false } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index 078110cc4..9b956a3dd 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -27,6 +27,7 @@ import mozilla.components.feature.top.sites.TopSite import mozilla.components.support.ktx.android.view.showKeyboard import mozilla.components.support.ktx.kotlin.isUrl import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.browser.BrowserFragmentDirections @@ -454,10 +455,12 @@ class DefaultSessionControlController( } override fun handleShowOnboardingDialog() { - navController.nav( - R.id.homeFragment, - HomeFragmentDirections.actionGlobalHomeOnboardingDialog() - ) + if (FeatureFlags.showHomeOnboarding) { + navController.nav( + R.id.homeFragment, + HomeFragmentDirections.actionGlobalHomeOnboardingDialog() + ) + } } override fun handleReadPrivacyNoticeClicked() { diff --git a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt index 0b429eeca..e82204ccc 100644 --- a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt @@ -178,6 +178,7 @@ class DefaultSessionControlControllerTest { } @Test + @Ignore("Until the feature is enabled again") fun handleShowOnboardingDialog() { createController().handleShowOnboardingDialog() From 0f07703c3eb51c08a48b17124038dbcf50a31f1f Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Tue, 5 Oct 2021 16:47:59 -0400 Subject: [PATCH 004/563] For #21611: Show the jump back in Contextual Hints independently of the home onboarding dialog. --- .../org/mozilla/fenix/ui/BookmarksTest.kt | 4 +- .../org/mozilla/fenix/ui/CollectionTest.kt | 2 +- .../java/org/mozilla/fenix/ui/HistoryTest.kt | 2 +- .../org/mozilla/fenix/ui/HomeScreenTest.kt | 2 +- .../mozilla/fenix/ui/NavigationToolbarTest.kt | 3 + .../fenix/ui/NoNetworkAccessStartupTests.kt | 2 +- .../org/mozilla/fenix/ui/SettingsAboutTest.kt | 2 +- .../mozilla/fenix/ui/SettingsBasicsTest.kt | 4 +- .../mozilla/fenix/ui/SettingsPrivacyTest.kt | 6 +- .../java/org/mozilla/fenix/ui/SmokeTest.kt | 18 ++-- .../StrictEnhancedTrackingProtectionTest.kt | 4 +- .../mozilla/fenix/ui/TabbedBrowsingTest.kt | 5 +- .../mozilla/fenix/ui/ThreeDotMenuMainTest.kt | 2 +- .../java/org/mozilla/fenix/ui/TopSitesTest.kt | 10 +-- .../debug/res/raw/initial_experiments.json | 2 +- .../home/sessioncontrol/SessionControlView.kt | 9 +- .../HomeOnboardingDialogFragment.kt | 66 -------------- .../fenix/onboarding/JumpBackInCFRDialog.kt | 89 +++++++++++++++++++ .../java/org/mozilla/fenix/utils/Settings.kt | 8 ++ app/src/main/res/values/preference_keys.xml | 2 + 20 files changed, 144 insertions(+), 98 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/onboarding/JumpBackInCFRDialog.kt diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt index 6e6333359..98be18980 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt @@ -52,6 +52,8 @@ class BookmarksTest { dispatcher = AndroidAssetDispatcher() start() } + val settings = activityTestRule.activity.settings() + settings.shouldShowJumpBackInCFR = false } @After @@ -346,7 +348,7 @@ class BookmarksTest { @Test fun openSelectionInNewTabTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) browserScreen { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt index 926e93710..3062db390 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt @@ -40,7 +40,7 @@ class CollectionTest { @Before fun setUp() { - activityTestRule.activity.applicationContext.settings().hasShownHomeOnboardingDialog = true + activityTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt index 448be81ce..094080b47 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt @@ -43,7 +43,7 @@ class HistoryTest { @Before fun setUp() { InstrumentationRegistry.getInstrumentation().targetContext.settings() - .hasShownHomeOnboardingDialog = true + .shouldShowJumpBackInCFR = false mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt index c69a90c77..dcd4fa299 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt @@ -119,7 +119,7 @@ class HomeScreenTest { @Test fun dismissOnboardingUsingHelpTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false homeScreen { verifyWelcomeHeader() }.openThreeDotMenu { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt index c0efe42f7..0fdaa1810 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt @@ -12,6 +12,7 @@ import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.TestAssetHelper @@ -41,6 +42,8 @@ class NavigationToolbarTest { dispatcher = AndroidAssetDispatcher() start() } + val settings = activityTestRule.activity.settings() + settings.shouldShowJumpBackInCFR = false } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt index 67edeaa26..072049707 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt @@ -56,7 +56,7 @@ class NoNetworkAccessStartupTests { fun networkInterruptedFromBrowserToHomeTest() { val url = "example.com" val settings = InstrumentationRegistry.getInstrumentation().targetContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false activityTestRule.launchActivity(null) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt index 05492c453..5e2a09bf0 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt @@ -77,7 +77,7 @@ class SettingsAboutTest { @Test fun verifyAboutFirefoxPreview() { val settings = activityIntentTestRule.activity.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false homeScreen { }.openThreeDotMenu { }.openSettings { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt index 7dc939648..1b7072499 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt @@ -43,6 +43,8 @@ class SettingsBasicsTest { dispatcher = AndroidAssetDispatcher() start() } + val settings = activityIntentTestRule.activity.settings() + settings.shouldShowJumpBackInCFR = false } @After @@ -157,7 +159,7 @@ class SettingsBasicsTest { val fenixApp = activityIntentTestRule.activity.applicationContext as FenixApplication val webpage = getLoremIpsumAsset(mockWebServer).url val settings = fenixApp.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false // This value will represent the text size percentage the webpage will scale to. The default value is 100%. val textSizePercentage = 180 diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt index 8178901ad..cc58dbfd6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt @@ -47,7 +47,7 @@ class SettingsPrivacyTest { } val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false } @After @@ -223,7 +223,7 @@ class SettingsPrivacyTest { fun neverSaveLoginFromPromptTest() { val saveLoginTest = TestAssetHelper.getSaveLoginAsset(mockWebServer) val settings = activityTestRule.activity.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false navigationToolbar { }.enterURLAndEnterToBrowser(saveLoginTest.url) { @@ -330,7 +330,7 @@ class SettingsPrivacyTest { @Test fun launchLinksInPrivateToggleOffStateDoesntChangeTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) setOpenLinksInPrivateOn() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index 701f34aa7..ef975a528 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -108,7 +108,7 @@ class SmokeTest { // So we are initializing this here instead of in all related tests. browserStore = activityTestRule.activity.components.core.store - activityTestRule.activity.applicationContext.settings().hasShownHomeOnboardingDialog = true + activityTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() start() @@ -312,7 +312,7 @@ class SmokeTest { // Verifies the Add to top sites option in a tab's 3 dot menu fun openMainMenuAddTopSiteTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -824,7 +824,7 @@ class SmokeTest { @Ignore("https://github.com/mozilla-mobile/fenix/issues/21397") fun createFirstCollectionTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2) @@ -858,7 +858,7 @@ class SmokeTest { @Ignore("https://github.com/mozilla-mobile/fenix/issues/21397") fun verifyExpandedCollectionItemsTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val webPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { @@ -912,7 +912,7 @@ class SmokeTest { @Test fun shareCollectionTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val webPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -938,7 +938,7 @@ class SmokeTest { // caution when making changes to it, so they don't block the builds fun deleteCollectionTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val webPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { @@ -1357,7 +1357,7 @@ class SmokeTest { @Test fun goToHomeScreenBottomToolbarTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { @@ -1371,7 +1371,7 @@ class SmokeTest { @Test fun goToHomeScreenTopToolbarTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -1441,7 +1441,7 @@ class SmokeTest { @Test fun alwaysStartOnHomeTest() { val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt index d22b12206..1a5320a1b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt @@ -44,7 +44,9 @@ class StrictEnhancedTrackingProtectionTest { start() } - activityTestRule.activity.settings().setStrictETP() + val settings = activityTestRule.activity.settings() + settings.setStrictETP() + settings.shouldShowJumpBackInCFR = false } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index 685e3bc90..abe2f4ce9 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -48,14 +48,11 @@ class TabbedBrowsingTest { @Before fun setUp() { - activityTestRule.activity.applicationContext.settings().hasShownHomeOnboardingDialog = true + activityTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() start() } - - val settings = activityTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt index c1689eac7..ac0d9e7da 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt @@ -29,7 +29,7 @@ class ThreeDotMenuMainTest { @Before fun setUp() { - activityTestRule.activity.applicationContext.settings().hasShownHomeOnboardingDialog = true + activityTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() start() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt index d989813ee..1e3616734 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt @@ -50,7 +50,7 @@ class TopSitesTest { @Test fun verifyAddToFirefoxHome() { val settings = activityIntentTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val defaultWebPageTitle = "Test_Page_1" @@ -70,7 +70,7 @@ class TopSitesTest { @Test fun verifyOpenTopSiteNormalTab() { val settings = activityIntentTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val defaultWebPageTitle = "Test_Page_1" @@ -100,7 +100,7 @@ class TopSitesTest { @Test fun verifyOpenTopSitePrivateTab() { val settings = activityIntentTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val defaultWebPageTitle = "Test_Page_1" @@ -124,7 +124,7 @@ class TopSitesTest { @Test fun verifyRenameTopSite() { val settings = activityIntentTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val defaultWebPageTitle = "Test_Page_1" val defaultWebPageTitleNew = "Test_Page_2" @@ -150,7 +150,7 @@ class TopSitesTest { @Test fun verifyRemoveTopSite() { val settings = activityIntentTestRule.activity.applicationContext.settings() - settings.hasShownHomeOnboardingDialog = true + settings.shouldShowJumpBackInCFR = false val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val defaultWebPageTitle = "Test_Page_1" diff --git a/app/src/debug/res/raw/initial_experiments.json b/app/src/debug/res/raw/initial_experiments.json index 3514af8ee..6bced9269 100644 --- a/app/src/debug/res/raw/initial_experiments.json +++ b/app/src/debug/res/raw/initial_experiments.json @@ -12,7 +12,7 @@ "value": { "sections-enabled": { "topSites": true, - "recentExplorations": false, + "recentExplorations": true, "recentlySaved": false, "jumpBackIn": false, "pocket": false diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt index 0903563cf..576811848 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt @@ -24,6 +24,7 @@ import org.mozilla.fenix.home.HomeScreenViewModel import org.mozilla.fenix.home.Mode import org.mozilla.fenix.home.OnboardingState import org.mozilla.fenix.home.recenttabs.RecentTab +import org.mozilla.fenix.onboarding.JumpBackInCFRDialog import org.mozilla.fenix.utils.Settings // This method got a little complex with the addition of the tab tray feature flag @@ -197,7 +198,13 @@ class SessionControlView( init { view.apply { adapter = sessionControlAdapter - layoutManager = LinearLayoutManager(containerView.context) + layoutManager = object : LinearLayoutManager(containerView.context) { + override fun onLayoutCompleted(state: RecyclerView.State?) { + super.onLayoutCompleted(state) + + JumpBackInCFRDialog(view).showIfNeeded() + } + } val itemTouchHelper = ItemTouchHelper( SwipeToDeleteCallback( diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/HomeOnboardingDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/onboarding/HomeOnboardingDialogFragment.kt index f776bead0..ad078aadb 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/HomeOnboardingDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/HomeOnboardingDialogFragment.kt @@ -4,22 +4,14 @@ package org.mozilla.fenix.onboarding -import android.app.Dialog -import android.content.Context -import android.graphics.Color -import android.graphics.drawable.ColorDrawable import android.os.Bundle -import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment -import androidx.recyclerview.widget.RecyclerView import org.mozilla.fenix.R import org.mozilla.fenix.databinding.FragmentOnboardingHomeDialogBinding -import org.mozilla.fenix.databinding.OnboardingJumpBackInCfrBinding import org.mozilla.fenix.ext.settings -import org.mozilla.fenix.home.recenttabs.view.RecentTabsHeaderViewHolder /** * Dialog displayed once when one or multiples of these sections are shown in the home screen @@ -45,65 +37,7 @@ class HomeOnboardingDialogFragment : DialogFragment() { context?.settings()?.let { settings -> settings.hasShownHomeOnboardingDialog = true } - showJumpCFR() dismiss() } } - - private fun showJumpCFR() { - val jumpBackInView = findJumpBackInView() - jumpBackInView?.let { - val crfDialog = createJumpCRF(anchor = jumpBackInView) - crfDialog?.show() - } - } - - private fun findJumpBackInView(): View? { - val list = activity?.findViewById(R.id.sessionControlRecyclerView) - val count = list?.adapter?.itemCount ?: return null - - for (index in 0..count) { - val viewHolder = list.findViewHolderForAdapterPosition(index) - if (viewHolder is RecentTabsHeaderViewHolder) { - return viewHolder.containerView - } - } - return null - } - - private fun createJumpCRF(anchor: View): Dialog? { - val context: Context = requireContext() - val anchorPosition = IntArray(2) - val popupBinding = OnboardingJumpBackInCfrBinding.inflate(LayoutInflater.from(context)) - val popup = Dialog(context) - - popup.apply { - setContentView(popupBinding.root) - setCancelable(false) - // removing title or setting it as an empty string does not prevent a11y services from assigning one - setTitle(" ") - } - popupBinding.closeInfoBanner.setOnClickListener { - popup.dismiss() - } - - anchor.getLocationOnScreen(anchorPosition) - val (x, y) = anchorPosition - - if (x == 0 && y == 0) { - return null - } - - popupBinding.root.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) - - popup.window?.apply { - val attr = attributes - setGravity(Gravity.START or Gravity.TOP) - attr.x = x - attr.y = y - popupBinding.root.measuredHeight - attributes = attr - setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - } - return popup - } } diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/JumpBackInCFRDialog.kt b/app/src/main/java/org/mozilla/fenix/onboarding/JumpBackInCFRDialog.kt new file mode 100644 index 000000000..31a87ae3a --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/onboarding/JumpBackInCFRDialog.kt @@ -0,0 +1,89 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.onboarding + +import android.app.Dialog +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import org.mozilla.fenix.databinding.OnboardingJumpBackInCfrBinding +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.home.recenttabs.view.RecentTabsHeaderViewHolder + +/** + * Dialog displayed once when the jump back in section is shown in the home screen. + */ +class JumpBackInCFRDialog(val recyclerView: RecyclerView) { + + /** + * Try to show the crf dialog if it hasn't been shown before. + */ + fun showIfNeeded() { + val jumpBackInView = findJumpBackInView() + jumpBackInView?.let { + val crfDialog = createJumpCRF(anchor = jumpBackInView) + crfDialog?.let { + val context = jumpBackInView.context + context.settings().shouldShowJumpBackInCFR = false + it.show() + } + } + } + + private fun findJumpBackInView(): View? { + val count = recyclerView.adapter?.itemCount ?: return null + + for (index in 0..count) { + val viewHolder = recyclerView.findViewHolderForAdapterPosition(index) + if (viewHolder is RecentTabsHeaderViewHolder) { + return viewHolder.containerView + } + } + return null + } + + private fun createJumpCRF(anchor: View): Dialog? { + val context: Context = recyclerView.context + if (!context.settings().shouldShowJumpBackInCFR) { + return null + } + val anchorPosition = IntArray(2) + val popupBinding = OnboardingJumpBackInCfrBinding.inflate(LayoutInflater.from(context)) + val popup = Dialog(context) + + popup.apply { + setContentView(popupBinding.root) + setCancelable(false) + // removing title or setting it as an empty string does not prevent a11y services from assigning one + setTitle(" ") + } + popupBinding.closeInfoBanner.setOnClickListener { + popup.dismiss() + } + + anchor.getLocationOnScreen(anchorPosition) + val (x, y) = anchorPosition + + if (x == 0 && y == 0) { + return null + } + + popupBinding.root.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) + + popup.window?.apply { + val attr = attributes + setGravity(Gravity.START or Gravity.TOP) + attr.x = x + attr.y = y - popupBinding.root.measuredHeight + attributes = attr + setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + } + return popup + } +} diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index a7b745972..a930e80ac 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -837,6 +837,14 @@ class Settings(private val appContext: Context) : PreferencesHolder { default = true ) + /** + * Indicates if the jump back in CRF should be shown. + */ + var shouldShowJumpBackInCFR by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_should_show_jump_back_in_tabs_popup), + default = true + ) + fun getSitePermissionsPhoneFeatureAction( feature: PhoneFeature, default: Action = Action.ASK_TO_ALLOW diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index d3d2873fa..8dfec3df8 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -227,6 +227,8 @@ pref_key_should_show_inactive_tabs_popup + + pref_key_should_show_jump_back_in_tabs_popup pref_key_migrating_from_fenix_nightly_tip From 5208f74cd7834b2d4e68a072bd50882de4d43c31 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Fri, 17 Sep 2021 16:38:36 +0200 Subject: [PATCH 005/563] SearchDialogFragment: Start to split consumeFrom() into independent observers that trigger less often --- .../fenix/search/SearchDialogFragment.kt | 96 +++++++++++++------ .../fenix/search/awesomebar/AwesomeBarView.kt | 32 +++++-- 2 files changed, 94 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt index bd0a8e1de..ecb2d38dc 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt @@ -52,6 +52,7 @@ import mozilla.components.support.ktx.android.content.hasCamera import mozilla.components.support.ktx.android.content.isPermissionGranted import mozilla.components.support.ktx.android.content.res.getSpanned import mozilla.components.support.ktx.android.view.hideKeyboard +import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import mozilla.components.ui.autocomplete.InlineAutocompleteEditText import org.mozilla.fenix.BrowserDirection @@ -66,6 +67,7 @@ import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.search.awesomebar.AwesomeBarView +import org.mozilla.fenix.search.awesomebar.toSearchProviderState import org.mozilla.fenix.search.toolbar.ToolbarView import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.widget.VoiceSearchActivity @@ -82,7 +84,6 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { private lateinit var store: SearchDialogFragmentStore private lateinit var toolbarView: ToolbarView private lateinit var awesomeBarView: AwesomeBarView - private var firstUpdate = true private val qrFeature = ViewBoundFeatureWrapper() private val speechIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) @@ -229,8 +230,8 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { return binding.root } - @ExperimentalCoroutinesApi @SuppressWarnings("LongMethod") + @ExperimentalCoroutinesApi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -340,26 +341,65 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { updateAccessibilityTraversalOrder() } + observeClipboardState() + observeAwesomeBarState() + observeShortcutsState() + observeSuggestionProvidersState() + consumeFrom(store) { - /* - * firstUpdate is used to make sure we keep the awesomebar hidden on the first run - * of the searchFragmentDialog. We only turn it false after the user has changed the - * query as consumeFrom may run several times on fragment start due to state updates. - * */ - if (it.url != it.query) firstUpdate = false - binding.awesomeBar.visibility = if (shouldShowAwesomebar(it)) View.VISIBLE else View.INVISIBLE updateSearchSuggestionsHintVisibility(it) - updateClipboardSuggestion(it) - updateToolbarContentDescription(it) - updateSearchShortcutsIcon(it) + updateToolbarContentDescription(it.searchEngineSource) toolbarView.update(it) awesomeBarView.update(it) addVoiceSearchButton(it) } } - private fun shouldShowAwesomebar(searchFragmentState: SearchFragmentState) = - !firstUpdate && searchFragmentState.query.isNotBlank() || searchFragmentState.showSearchShortcuts + @ExperimentalCoroutinesApi + private fun observeSuggestionProvidersState() = consumeFlow(store) { flow -> + flow.map { state -> state.toSearchProviderState() } + .ifChanged() + .collect { state -> awesomeBarView.updateSuggestionProvidersVisibility(state) } + } + + @ExperimentalCoroutinesApi + private fun observeShortcutsState() = consumeFlow(store) { flow -> + flow.ifAnyChanged { state -> arrayOf(state.areShortcutsAvailable, state.showSearchShortcuts) } + .collect { state -> updateSearchShortcutsIcon(state.areShortcutsAvailable, state.showSearchShortcuts) } + } + + @ExperimentalCoroutinesApi + private fun observeAwesomeBarState() = consumeFlow(store) { flow -> + /* + * firstUpdate is used to make sure we keep the awesomebar hidden on the first run + * of the searchFragmentDialog. We only turn it false after the user has changed the + * query as consumeFrom may run several times on fragment start due to state updates. + * */ + + flow.map { state -> state.url != state.query && state.query.isNotBlank() || state.showSearchShortcuts } + .ifChanged() + .collect { shouldShowAwesomebar -> + binding.awesomeBar.visibility = if (shouldShowAwesomebar) { + View.VISIBLE + } else { + View.INVISIBLE + } + } + } + + @ExperimentalCoroutinesApi + private fun observeClipboardState() = consumeFlow(store) { flow -> + flow.map { state -> + val shouldShowView = state.showClipboardSuggestions && + state.query.isEmpty() && + !state.clipboardUrl.isNullOrEmpty() && !state.showSearchShortcuts + Pair(shouldShowView, state.clipboardUrl) + } + .ifChanged() + .collect { (shouldShowView, clipboardUrl) -> + updateClipboardSuggestion(shouldShowView, clipboardUrl) + } + } private fun updateAccessibilityTraversalOrder() { val searchWrapperId = binding.searchWrapper.id @@ -602,11 +642,10 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { private fun isSpeechAvailable(): Boolean = speechIntent.resolveActivity(requireContext().packageManager) != null - private fun updateClipboardSuggestion(searchState: SearchFragmentState) { - val shouldShowView = searchState.showClipboardSuggestions && - searchState.query.isEmpty() && - !searchState.clipboardUrl.isNullOrEmpty() && !searchState.showSearchShortcuts - + private fun updateClipboardSuggestion( + shouldShowView: Boolean, + clipboardUrl: String? + ) { binding.fillLinkFromClipboard.isVisible = shouldShowView binding.fillLinkDivider.isVisible = shouldShowView binding.pillWrapperDivider.isVisible = @@ -615,32 +654,33 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { binding.clipboardTitle.isVisible = shouldShowView binding.linkIcon.isVisible = shouldShowView - binding.clipboardUrl.text = searchState.clipboardUrl + binding.clipboardUrl.text = clipboardUrl binding.fillLinkFromClipboard.contentDescription = "${binding.clipboardTitle.text}, ${binding.clipboardUrl.text}." - if (searchState.clipboardUrl != null && !((activity as HomeActivity).browsingModeManager.mode.isPrivate)) { - requireComponents.core.engine.speculativeConnect(searchState.clipboardUrl) + if (clipboardUrl != null && !((activity as HomeActivity).browsingModeManager.mode.isPrivate)) { + requireComponents.core.engine.speculativeConnect(clipboardUrl) } } - private fun updateToolbarContentDescription(searchState: SearchFragmentState) { + private fun updateToolbarContentDescription(source: SearchEngineSource) { val urlView = toolbarView.view .findViewById(R.id.mozac_browser_toolbar_edit_url_view) - searchState.searchEngineSource.searchEngine?.let { engine -> + source.searchEngine?.let { engine -> toolbarView.view.contentDescription = engine.name + ", " + urlView.hint } urlView?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO } - private fun updateSearchShortcutsIcon(searchState: SearchFragmentState) { + private fun updateSearchShortcutsIcon( + areShortcutsAvailable: Boolean, + showShortcuts: Boolean + ) { view?.apply { - binding.searchEnginesShortcutButton.isVisible = searchState.areShortcutsAvailable - - val showShortcuts = searchState.showSearchShortcuts + binding.searchEnginesShortcutButton.isVisible = areShortcutsAvailable binding.searchEnginesShortcutButton.isChecked = showShortcuts val color = if (showShortcuts) R.attr.contrastText else R.attr.primaryText diff --git a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt index 959953f56..38e1a6190 100644 --- a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt +++ b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt @@ -202,8 +202,6 @@ class AwesomeBarView( } fun update(state: SearchFragmentState) { - updateSuggestionProvidersVisibility(state) - // Do not make suggestions based on user's current URL unless it's a search shortcut if (state.query.isNotEmpty() && state.query == state.url && !state.showSearchShortcuts) { return @@ -212,7 +210,9 @@ class AwesomeBarView( view.onInputChanged(state.query) } - private fun updateSuggestionProvidersVisibility(state: SearchFragmentState) { + fun updateSuggestionProvidersVisibility( + state: SearchProviderState + ) { if (state.showSearchShortcuts) { handleDisplayShortcutsProviders() return @@ -244,7 +244,9 @@ class AwesomeBarView( } @Suppress("ComplexMethod") - private fun getProvidersToAdd(state: SearchFragmentState): MutableSet { + private fun getProvidersToAdd( + state: SearchProviderState + ): MutableSet { val providersToAdd = mutableSetOf() if (state.showHistorySuggestions) { @@ -276,7 +278,7 @@ class AwesomeBarView( return providersToAdd } - private fun getProvidersToRemove(state: SearchFragmentState): MutableSet { + private fun getProvidersToRemove(state: SearchProviderState): MutableSet { val providersToRemove = mutableSetOf() providersToRemove.add(shortcutsEnginePickerProvider) @@ -308,7 +310,7 @@ class AwesomeBarView( return providersToRemove } - private fun getSelectedSearchSuggestionProvider(state: SearchFragmentState): List { + private fun getSelectedSearchSuggestionProvider(state: SearchProviderState): List { return when (state.searchEngineSource) { is SearchEngineSource.Default -> listOf( defaultSearchActionProvider, @@ -367,8 +369,26 @@ class AwesomeBarView( } } + data class SearchProviderState( + val showSearchShortcuts: Boolean, + val showHistorySuggestions: Boolean, + val showBookmarkSuggestions: Boolean, + val showSearchSuggestions: Boolean, + val showSyncedTabsSuggestions: Boolean, + val searchEngineSource: SearchEngineSource + ) + companion object { // Maximum number of suggestions returned from the history metadata storage. const val METADATA_SUGGESTION_LIMIT = 3 } } + +fun SearchFragmentState.toSearchProviderState() = AwesomeBarView.SearchProviderState( + showSearchShortcuts, + showHistorySuggestions, + showBookmarkSuggestions, + showSearchSuggestions, + showSyncedTabsSuggestions, + searchEngineSource +) From dd20d9877955430bbec8684a32c5333b78378010 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Wed, 6 Oct 2021 02:24:13 -0400 Subject: [PATCH 006/563] For #21729 - Refactor SectionHeader to use the right font size --- .../mozilla/fenix/compose/SectionHeader.kt | 44 +++---------------- .../pocket/PocketStoriesViewHolder.kt | 6 +-- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/compose/SectionHeader.kt b/app/src/main/java/org/mozilla/fenix/compose/SectionHeader.kt index b53c87c48..aa4f8016e 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/SectionHeader.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/SectionHeader.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.compose import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextOverflow @@ -28,41 +27,14 @@ fun SectionHeader( modifier: Modifier = Modifier ) { Text( - modifier = modifier, text = text, - style = TextStyle( - fontFamily = FontFamily(Font(R.font.metropolis_semibold)), - fontSize = 20.sp, - lineHeight = 20.sp - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = FirefoxTheme.colors.textPrimary - ) -} - -/** - * Default layout for the header of a screen section. - * - * @param text [String] to be styled as header and displayed. - * @param modifier [Modifier] to be applied to the [Text]. - */ -@Composable -fun HomeSectionHeader( - text: String, - modifier: Modifier = Modifier -) { - Text( modifier = modifier, - text = text, - style = TextStyle( - fontFamily = FontFamily(Font(R.font.metropolis_semibold)), - fontSize = 16.sp, - lineHeight = 20.sp - ), - maxLines = 1, + color = FirefoxTheme.colors.textPrimary, + fontSize = 16.sp, + fontFamily = FontFamily(Font(R.font.metropolis_semibold)), + lineHeight = 20.sp, overflow = TextOverflow.Ellipsis, - color = FirefoxTheme.colors.textPrimary + maxLines = 1 ) } @@ -71,9 +43,3 @@ fun HomeSectionHeader( private fun HeadingTextPreview() { SectionHeader(text = "Section title") } - -@Composable -@Preview -private fun HomeHeadingTextPreview() { - HomeSectionHeader(text = "Home section title") -} diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt index e3d357e2c..116ff8ff8 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt @@ -22,7 +22,7 @@ import androidx.recyclerview.widget.RecyclerView import mozilla.components.lib.state.ext.observeAsComposableState import mozilla.components.service.pocket.PocketRecommendedStory import org.mozilla.fenix.R -import org.mozilla.fenix.compose.HomeSectionHeader +import org.mozilla.fenix.compose.SectionHeader import org.mozilla.fenix.home.HomeFragmentStore import org.mozilla.fenix.theme.FirefoxTheme @@ -93,7 +93,7 @@ fun PocketStories( } Column(modifier = Modifier.padding(vertical = 44.dp)) { - HomeSectionHeader( + SectionHeader( text = stringResource(R.string.pocket_stories_header_1), modifier = Modifier .fillMaxWidth() @@ -106,7 +106,7 @@ fun PocketStories( Spacer(Modifier.height(24.dp)) - HomeSectionHeader( + SectionHeader( text = stringResource(R.string.pocket_stories_categories_header), modifier = Modifier .fillMaxWidth() From 23e51c250aa4563db2a3c1862102f5c3400a2d73 Mon Sep 17 00:00:00 2001 From: Roger Yang Date: Wed, 6 Oct 2021 10:03:27 -0400 Subject: [PATCH 007/563] No issue: Small layout update for Pocket Stories --- .../viewholders/pocket/PocketStoriesComposables.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt index d410cd8ad..bc2a152b2 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt @@ -85,7 +85,7 @@ fun PocketStory( imageUrl = imageUrl, onClick = { onStoryClick(story) }, title = { - TabTitle(text = story.title, maxLines = 3) + TabTitle(text = story.title, maxLines = 2) }, subtitle = { if (isValidPublisher && isValidTimeToRead) { @@ -168,7 +168,7 @@ fun PocketStoriesCategories( ) { Box(modifier = modifier) { StaggeredHorizontalGrid( - horizontalItemsSpacing = 16.dp + horizontalItemsSpacing = 8.dp ) { categories.filter { it.name != POCKET_STORIES_DEFAULT_CATEGORY_NAME }.forEach { category -> SelectableChip(category.name, selections.map { it.name }.contains(category.name)) { From 099e463b4f8302fd4ab3bdc46b1e4ca277e00702 Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Wed, 1 Sep 2021 11:32:36 +0200 Subject: [PATCH 008/563] Issue #21102: Set compileSdkVersion to 31. --- app/src/main/java/org/mozilla/fenix/ext/String.kt | 1 + .../main/java/org/mozilla/fenix/search/SearchDialogFragment.kt | 1 + .../mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt | 1 + buildSrc/src/main/java/Config.kt | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/ext/String.kt b/app/src/main/java/org/mozilla/fenix/ext/String.kt index cbbd5705d..04bf08c3e 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/String.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/String.kt @@ -81,6 +81,7 @@ fun String.toShortUrl(publicSuffixList: PublicSuffixList): String { } // impl via FFTV https://searchfox.org/mozilla-mobile/source/firefox-echo-show/app/src/main/java/org/mozilla/focus/utils/FormattedDomain.java#129 +@Suppress("DEPRECATION") fun String.isIpv4(): Boolean = Patterns.IP_ADDRESS.matcher(this).matches() // impl via FFiOS: https://github.com/mozilla-mobile/firefox-ios/blob/deb9736c905cdf06822ecc4a20152df7b342925d/Shared/Extensions/NSURLExtensions.swift#L292 diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt index ecb2d38dc..d703474ca 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt @@ -448,6 +448,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { if (!dialogHandledAction) { val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + @Suppress("DEPRECATION") imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0) } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt index 510f7c8ea..c2353524c 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt @@ -109,6 +109,7 @@ class AddLoginFragment : Fragment(R.layout.fragment_add_login) { binding.hostnameText.requestFocus() val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + @Suppress("DEPRECATION") imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0) binding.clearHostnameTextButton.setOnClickListener { diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 7325ebf00..46638a4e8 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -13,7 +13,7 @@ import java.util.Locale object Config { // Synchronized build configuration for all modules - const val compileSdkVersion = 30 + const val compileSdkVersion = 31 const val minSdkVersion = 21 const val targetSdkVersion = 30 From f4750f3c357952ebc84429ebefa1aada5a293ecd Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Wed, 6 Oct 2021 15:34:59 +0000 Subject: [PATCH 009/563] Update Android Components version to 95.0.20211006143357. --- buildSrc/src/main/java/AndroidComponents.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index d569a3cec..43ab69898 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "95.0.20211005200555" + const val VERSION = "95.0.20211006143357" } From 3632ed77d5d76c1ff47dd7fc2b319dd5092e7a01 Mon Sep 17 00:00:00 2001 From: Roger Yang Date: Wed, 6 Oct 2021 14:32:30 -0400 Subject: [PATCH 010/563] No issue: Update Pocket categories spacing to 16dp. --- .../viewholders/pocket/PocketStoriesComposables.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt index bc2a152b2..8860ffb9e 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt @@ -168,7 +168,8 @@ fun PocketStoriesCategories( ) { Box(modifier = modifier) { StaggeredHorizontalGrid( - horizontalItemsSpacing = 8.dp + horizontalItemsSpacing = 16.dp, + verticalItemsSpacing = 16.dp ) { categories.filter { it.name != POCKET_STORIES_DEFAULT_CATEGORY_NAME }.forEach { category -> SelectableChip(category.name, selections.map { it.name }.contains(category.name)) { From 1f97ca6ce666183fd75272a5ed11567a22bef03e Mon Sep 17 00:00:00 2001 From: Noah Bond <87384386+MozillaNoah@users.noreply.github.com> Date: Wed, 6 Oct 2021 14:01:16 -0700 Subject: [PATCH 011/563] For #21437 - Relocated Home-related settings to its dedicated sub screen (#21722) * For #21437 - Relocated Home-related settings to its dedicated sub screen * For #21437 - Updated show top sites toggle text * PR: Fixed lint warning. Reverted preference keys * PR: added ignore for UI test * PR: Added ignore for UI test --- .../mozilla/fenix/ui/SettingsBasicsTest.kt | 1 + .../java/org/mozilla/fenix/ui/SmokeTest.kt | 2 +- .../ui/robots/SettingsSubMenuTabsRobot.kt | 13 --- .../fenix/settings/CustomizationFragment.kt | 51 ---------- .../fenix/settings/HomeSettingsFragment.kt | 99 +++++++++++++++++++ .../fenix/settings/SettingsFragment.kt | 3 + .../fenix/settings/TabsSettingsFragment.kt | 16 --- .../java/org/mozilla/fenix/utils/Settings.kt | 15 +-- app/src/main/res/navigation/nav_graph.xml | 11 +++ app/src/main/res/values/preference_keys.xml | 1 + app/src/main/res/values/strings.xml | 26 +++-- .../res/xml/customization_preferences.xml | 29 ------ app/src/main/res/xml/home_preferences.xml | 56 +++++++++++ app/src/main/res/xml/preferences.xml | 5 + ...preferences_default_browser_experiment.xml | 5 + app/src/main/res/xml/tabs_preferences.xml | 24 ----- .../org/mozilla/fenix/utils/SettingsTest.kt | 24 ++--- 17 files changed, 221 insertions(+), 160 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt create mode 100644 app/src/main/res/xml/home_preferences.xml diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt index 1b7072499..d3b35ca4f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt @@ -63,6 +63,7 @@ class SettingsBasicsTest { } } + @Ignore // to be fixed https://github.com/mozilla-mobile/fenix/issues/21754 @Test // Walks through settings menu and sub-menus to ensure all items are present fun settingsMenuBasicsItemsTests() { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index ef975a528..392f15332 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -1434,10 +1434,10 @@ class SmokeTest { }.openTabsSubMenu { verifyTabViewOptions() verifyCloseTabsOptions() - verifyStartOnHomeOptions() } } + @Ignore // to be fixed here https://github.com/mozilla-mobile/fenix/issues/21747 @Test fun alwaysStartOnHomeTest() { val settings = activityTestRule.activity.applicationContext.settings() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuTabsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuTabsRobot.kt index fc1c33656..a539972c7 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuTabsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuTabsRobot.kt @@ -28,8 +28,6 @@ class SettingsSubMenuTabsRobot { fun verifyCloseTabsOptions() = assertCloseTabsOptions() - fun verifyStartOnHomeOptions() = assertStartOnHomeOptions() - fun clickAlwaysStartOnHomeToggle() { scrollToElementByText("Move old tabs to inactive") alwaysStartOnHomeToggle().click() @@ -70,17 +68,6 @@ private fun assertCloseTabsOptions() { .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } -private fun assertStartOnHomeOptions() { - // Scroll to ensure all the items are visible. - scrollToElementByText("Never") - startOnHomeHeading() - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - afterFourHoursToggle() - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - alwaysStartOnHomeToggle() - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -} - private fun tabViewHeading() = onView(withText("Tab view")) private fun listToggle() = onView(withText("List")) diff --git a/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt index c6a1267a6..b0d352f37 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt @@ -9,7 +9,6 @@ import android.os.Build import android.os.Build.VERSION.SDK_INT import android.os.Bundle import androidx.appcompat.app.AppCompatDelegate -import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import org.mozilla.fenix.FeatureFlags @@ -51,7 +50,6 @@ class CustomizationFragment : PreferenceFragmentCompat() { bindAutoBatteryTheme() setupRadioGroups() setupToolbarCategory() - setupHomeCategory() setupGesturesCategory() } @@ -140,37 +138,6 @@ class CustomizationFragment : PreferenceFragmentCompat() { addToRadioGroup(topPreference, bottomPreference) } - private fun setupHomeCategory() { - requirePreference(R.string.pref_key_enable_top_frecent_sites).apply { - isChecked = context.settings().showTopFrecentSites - onPreferenceChangeListener = CustomizeHomeMetricsUpdater() - } - - requirePreference(R.string.pref_key_recent_tabs).apply { - isVisible = FeatureFlags.showRecentTabsFeature - isChecked = context.settings().showRecentTabsFeature - onPreferenceChangeListener = CustomizeHomeMetricsUpdater() - } - - requirePreference(R.string.pref_key_recent_bookmarks).apply { - isVisible = FeatureFlags.recentBookmarksFeature - isChecked = context.settings().showRecentBookmarksFeature - onPreferenceChangeListener = CustomizeHomeMetricsUpdater() - } - - requirePreference(R.string.pref_key_pocket_homescreen_recommendations).apply { - isVisible = FeatureFlags.isPocketRecommendationsFeatureEnabled(context) - isChecked = context.settings().showPocketRecommendationsFeature - onPreferenceChangeListener = CustomizeHomeMetricsUpdater() - } - - requirePreference(R.string.pref_key_history_metadata_feature).apply { - isVisible = FeatureFlags.historyMetadataUIFeature - isChecked = context.settings().historyMetadataUIFeature - onPreferenceChangeListener = CustomizeHomeMetricsUpdater() - } - } - private fun setupGesturesCategory() { requirePreference(R.string.pref_key_website_pull_to_refresh).apply { isVisible = FeatureFlags.pullToRefreshEnabled @@ -186,22 +153,4 @@ class CustomizationFragment : PreferenceFragmentCompat() { onPreferenceChangeListener = SharedPreferenceUpdater() } } - - class CustomizeHomeMetricsUpdater : SharedPreferenceUpdater() { - override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { - try { - val context = preference.context - context.components.analytics.metrics.track( - Event.CustomizeHomePreferenceToggled( - preference.key, - newValue as Boolean, - context - ) - ) - } catch (e: IllegalArgumentException) { - // The event is not tracked - } - return super.onPreferenceChange(preference, newValue) - } - } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt new file mode 100644 index 000000000..370d2fb14 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt @@ -0,0 +1,99 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.settings + +import android.os.Bundle +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.SwitchPreference +import org.mozilla.fenix.FeatureFlags +import org.mozilla.fenix.R +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.ext.showToolbar +import org.mozilla.fenix.utils.view.addToRadioGroup + +/** + * Lets the user customize the home screen. + */ +class HomeSettingsFragment : PreferenceFragmentCompat() { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.home_preferences, rootKey) + } + + override fun onResume() { + super.onResume() + showToolbar(getString(R.string.preferences_home_2)) + setupPreferences() + } + + private fun setupPreferences() { + requirePreference(R.string.pref_key_enable_top_frecent_sites).apply { + isChecked = context.settings().showTopFrecentSites + onPreferenceChangeListener = CustomizeHomeMetricsUpdater() + } + + requirePreference(R.string.pref_key_recent_tabs).apply { + isVisible = FeatureFlags.showRecentTabsFeature + isChecked = context.settings().showRecentTabsFeature + onPreferenceChangeListener = CustomizeHomeMetricsUpdater() + } + + requirePreference(R.string.pref_key_recent_bookmarks).apply { + isVisible = FeatureFlags.recentBookmarksFeature + isChecked = context.settings().showRecentBookmarksFeature + onPreferenceChangeListener = CustomizeHomeMetricsUpdater() + } + + requirePreference(R.string.pref_key_pocket_homescreen_recommendations).apply { + isVisible = FeatureFlags.isPocketRecommendationsFeatureEnabled(context) + isChecked = context.settings().showPocketRecommendationsFeature + onPreferenceChangeListener = CustomizeHomeMetricsUpdater() + } + + requirePreference(R.string.pref_key_history_metadata_feature).apply { + isVisible = FeatureFlags.historyMetadataUIFeature + isChecked = context.settings().historyMetadataUIFeature + onPreferenceChangeListener = CustomizeHomeMetricsUpdater() + } + + val openingScreenRadioHomepage = + requirePreference(R.string.pref_key_start_on_home_always) + val openingScreenLastTab = + requirePreference(R.string.pref_key_start_on_home_never) + val openingScreenAfterFourHours = + requirePreference(R.string.pref_key_start_on_home_after_four_hours) + + requirePreference(R.string.pref_key_start_on_home_category).isVisible = + FeatureFlags.showStartOnHomeSettings + + addToRadioGroup( + openingScreenRadioHomepage, + openingScreenLastTab, + openingScreenAfterFourHours + ) + } + + inner class CustomizeHomeMetricsUpdater : SharedPreferenceUpdater() { + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + try { + val context = preference.context + context.components.analytics.metrics.track( + Event.CustomizeHomePreferenceToggled( + preference.key, + newValue as Boolean, + context + ) + ) + } catch (e: IllegalArgumentException) { + // The event is not tracked + } + return super.onPreferenceChange(preference, newValue) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt index 659549a15..220d0f187 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -242,6 +242,9 @@ class SettingsFragment : PreferenceFragmentCompat() { resources.getString(R.string.pref_key_tabs) -> { SettingsFragmentDirections.actionSettingsFragmentToTabsSettingsFragment() } + resources.getString(R.string.pref_key_home) -> { + SettingsFragmentDirections.actionSettingsFragmentToHomeSettingsFragment() + } resources.getString(R.string.pref_key_search_settings) -> { SettingsFragmentDirections.actionSettingsFragmentToSearchEngineFragment() } diff --git a/app/src/main/java/org/mozilla/fenix/settings/TabsSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/TabsSettingsFragment.kt index 964cfc409..5cc919db1 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/TabsSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/TabsSettingsFragment.kt @@ -29,9 +29,6 @@ class TabsSettingsFragment : PreferenceFragmentCompat() { private lateinit var radioOneDay: RadioButtonPreference private lateinit var radioOneWeek: RadioButtonPreference private lateinit var radioOneMonth: RadioButtonPreference - private lateinit var startOnHomeRadioFourHours: RadioButtonPreference - private lateinit var startOnHomeRadioAlways: RadioButtonPreference - private lateinit var startOnHomeRadioNever: RadioButtonPreference private lateinit var inactiveTabsCategory: PreferenceCategory private lateinit var inactiveTabs: SwitchPreference private lateinit var searchTermTabGroups: SwitchPreference @@ -70,13 +67,6 @@ class TabsSettingsFragment : PreferenceFragmentCompat() { radioOneWeek = requirePreference(R.string.pref_key_close_tabs_after_one_week) radioOneDay = requirePreference(R.string.pref_key_close_tabs_after_one_day) - startOnHomeRadioFourHours = requirePreference(R.string.pref_key_start_on_home_after_four_hours) - startOnHomeRadioAlways = requirePreference(R.string.pref_key_start_on_home_always) - startOnHomeRadioNever = requirePreference(R.string.pref_key_start_on_home_never) - - requirePreference(R.string.pref_key_start_on_home_category).isVisible = - FeatureFlags.showStartOnHomeSettings - inactiveTabs = requirePreference(R.string.pref_key_inactive_tabs).also { it.isChecked = it.context.settings().inactiveTabsAreEnabled it.onPreferenceChangeListener = SharedPreferenceUpdater() @@ -110,12 +100,6 @@ class TabsSettingsFragment : PreferenceFragmentCompat() { radioOneMonth, radioOneWeek ) - - addToRadioGroup( - startOnHomeRadioFourHours, - startOnHomeRadioAlways, - startOnHomeRadioNever - ) } private fun sendTabViewTelemetry() { diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index a930e80ac..1cf25e436 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -381,7 +381,7 @@ class Settings(private val appContext: Context) : PreferencesHolder { * Indicates if the user has selected the option to start on the home screen after * four hours of inactivity. */ - var startOnHomeAfterFourHours by booleanPreference( + var openHomepageAfterFourHoursOfInactivity by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_start_on_home_after_four_hours), default = true ) @@ -389,15 +389,16 @@ class Settings(private val appContext: Context) : PreferencesHolder { /** * Indicates if the user has selected the option to always start on the home screen. */ - var startOnHomeAlways by booleanPreference( + var alwaysOpenTheHomepageWhenOpeningTheApp by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_start_on_home_always), default = false ) /** - * Indicates if the user has selected the option to never start on the home screen. + * Indicates if the user has selected the option to never start on the home screen and have + * their last tab opened. */ - var startOnHomeNever by booleanPreference( + var alwaysOpenTheLastTabWhenOpeningTheApp by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_start_on_home_never), default = false ) @@ -407,9 +408,9 @@ class Settings(private val appContext: Context) : PreferencesHolder { */ fun shouldStartOnHome(): Boolean { return when { - startOnHomeAfterFourHours -> timeNowInMillis() - lastBrowseActivity >= FOUR_HOURS_MS - startOnHomeAlways -> true - startOnHomeNever -> false + openHomepageAfterFourHoursOfInactivity -> timeNowInMillis() - lastBrowseActivity >= FOUR_HOURS_MS + alwaysOpenTheHomepageWhenOpeningTheApp -> true + alwaysOpenTheLastTabWhenOpeningTheApp -> false else -> false } } diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 1a40d2449..f77ac80df 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -592,11 +592,22 @@ app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> + + pref_key_tab_view_list pref_key_tab_view_grid pref_key_tabs + pref_key_home pref_key_close_tabs_manually pref_key_close_tabs_after_one_day pref_key_close_tabs_after_one_week diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6039ed8ca..82a24648b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -367,7 +367,9 @@ Theme - Home + Home + + Homepage Gestures @@ -678,15 +680,23 @@ Auto-close open tabs - + - Start on home + Start on home + + Opening screen - After four hours + After four hours + + Homepage - Always + Always + + Last tab - Never + Never + + Homepage after four hours of inactivity Close manually @@ -1909,8 +1919,10 @@ To add a new top site, remove one. Touch and hold the site and select remove. OK, Got It + + Most visited top sites - Show most visited top sites + Show most visited top sites Show most visited sites diff --git a/app/src/main/res/xml/customization_preferences.xml b/app/src/main/res/xml/customization_preferences.xml index a5ff3da4c..cfd13f3aa 100644 --- a/app/src/main/res/xml/customization_preferences.xml +++ b/app/src/main/res/xml/customization_preferences.xml @@ -43,35 +43,6 @@ android:title="@string/preference_bottom_toolbar" /> - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index ab16a037d..e1e9be315 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -60,6 +60,11 @@ android:key="@string/pref_key_tabs" android:title="@string/preferences_tabs" /> + + + + - - - - - - - - - Date: Wed, 6 Oct 2021 16:38:18 -0400 Subject: [PATCH 012/563] For #21756 - Refactor TopSites out of home.sessioncontrol --- app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt | 2 +- .../fenix/home/sessioncontrol/SessionControlAdapter.kt | 2 +- .../viewholders => }/topsites/DefaultTopSitesView.kt | 2 +- .../viewholders => }/topsites/PagerIndicator.kt | 2 +- .../viewholders => }/topsites/TopSiteItemViewHolder.kt | 2 +- .../viewholders => topsites}/TopSitePagerViewHolder.kt | 3 +-- .../viewholders => topsites}/TopSiteViewHolder.kt | 3 +-- .../viewholders => }/topsites/TopSitesAdapter.kt | 2 +- .../viewholders => }/topsites/TopSitesPagerAdapter.kt | 5 ++--- .../java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt | 2 +- app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt | 2 +- .../mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt | 2 +- .../mozilla/fenix/tabstray/browser/TabGroupListAdapter.kt | 2 +- app/src/main/res/layout/component_top_sites_pager.xml | 2 +- .../viewholders => }/topsites/TopSiteItemViewHolderTest.kt | 2 +- .../viewholders => topsites}/TopSiteViewHolderTest.kt | 2 +- .../viewholders => }/topsites/TopSitesAdapterTest.kt | 2 +- .../viewholders => }/topsites/TopSitesPagerAdapterTest.kt | 2 +- .../org/mozilla/fenix/perf/StartupReportFullyDrawnTest.kt | 2 +- 19 files changed, 20 insertions(+), 23 deletions(-) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/DefaultTopSitesView.kt (90%) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/PagerIndicator.kt (97%) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/TopSiteItemViewHolder.kt (98%) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => topsites}/TopSitePagerViewHolder.kt (95%) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => topsites}/TopSiteViewHolder.kt (89%) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/TopSitesAdapter.kt (97%) rename app/src/main/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/TopSitesPagerAdapter.kt (94%) rename app/src/test/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/TopSiteItemViewHolderTest.kt (97%) rename app/src/test/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => topsites}/TopSiteViewHolderTest.kt (96%) rename app/src/test/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/TopSitesAdapterTest.kt (94%) rename app/src/test/java/org/mozilla/fenix/home/{sessioncontrol/viewholders => }/topsites/TopSitesPagerAdapterTest.kt (98%) diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index c2998bc21..b20528d8f 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -118,7 +118,7 @@ import org.mozilla.fenix.home.sessioncontrol.SessionControlView import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.pocket.DefaultPocketStoriesController import org.mozilla.fenix.home.sessioncontrol.viewholders.pocket.PocketRecommendedStoriesCategory -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.DefaultTopSitesView +import org.mozilla.fenix.home.topsites.DefaultTopSitesView import org.mozilla.fenix.onboarding.FenixOnboarding import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils.SumoTopic.HELP diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt index 6f9d299ca..2ee4d43ce 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt @@ -33,7 +33,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonView import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder +import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.ExperimentDefaultBrowserCardViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/DefaultTopSitesView.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt similarity index 90% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/DefaultTopSitesView.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt index 63fd9c2c9..d850cce8f 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/DefaultTopSitesView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders.topsites +package org.mozilla.fenix.home.topsites import mozilla.components.feature.top.sites.TopSite import mozilla.components.feature.top.sites.view.TopSitesView diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/PagerIndicator.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/PagerIndicator.kt similarity index 97% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/PagerIndicator.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/PagerIndicator.kt index dd5acdf5e..f06cbcbe5 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/PagerIndicator.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/PagerIndicator.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders.topsites +package org.mozilla.fenix.home.topsites import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSiteItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt similarity index 98% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSiteItemViewHolder.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt index d4ade4c27..2e2b2b8eb 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSiteItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders.topsites +package org.mozilla.fenix.home.topsites import android.annotation.SuppressLint import android.content.Context diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TopSitePagerViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt similarity index 95% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TopSitePagerViewHolder.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt index 89b0692bb..4777d88f0 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TopSitePagerViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders +package org.mozilla.fenix.home.topsites import android.view.View import androidx.core.view.isVisible @@ -15,7 +15,6 @@ import org.mozilla.fenix.databinding.ComponentTopSitesPagerBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.home.sessioncontrol.AdapterItem import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.TopSitesPagerAdapter class TopSitePagerViewHolder( view: View, diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TopSiteViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt similarity index 89% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TopSiteViewHolder.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt index 6f7a9ba3a..a5c163122 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TopSiteViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders +package org.mozilla.fenix.home.topsites import android.view.View import androidx.recyclerview.widget.RecyclerView @@ -10,7 +10,6 @@ import mozilla.components.feature.top.sites.TopSite import org.mozilla.fenix.R import org.mozilla.fenix.databinding.ComponentTopSitesBinding import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.TopSitesAdapter import org.mozilla.fenix.utils.AccessibilityGridLayoutManager class TopSiteViewHolder( diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSitesAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt similarity index 97% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSitesAdapter.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt index 587b6a86f..579aca289 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSitesAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders.topsites +package org.mozilla.fenix.home.topsites import android.view.LayoutInflater import android.view.ViewGroup diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSitesPagerAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt similarity index 94% rename from app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSitesPagerAdapter.kt rename to app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt index b13ba54d8..0d35277da 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/topsites/TopSitesPagerAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.home.sessioncontrol.viewholders.topsites +package org.mozilla.fenix.home.topsites import android.view.LayoutInflater import android.view.ViewGroup @@ -12,8 +12,7 @@ import androidx.recyclerview.widget.ListAdapter import mozilla.components.feature.top.sites.TopSite import org.mozilla.fenix.home.sessioncontrol.AdapterItem.TopSitePagerPayload import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor -import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder.Companion.TOP_SITES_PER_PAGE -import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSiteViewHolder +import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder.Companion.TOP_SITES_PER_PAGE class TopSitesPagerAdapter( private val interactor: TopSiteInteractor diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt index 0199542e1..800272b08 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupReportFullyDrawn.kt @@ -10,7 +10,7 @@ import androidx.core.view.doOnPreDraw import mozilla.components.support.ktx.android.view.reportFullyDrawnSafe import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.TopSiteItemViewHolder +import org.mozilla.fenix.home.topsites.TopSiteItemViewHolder import org.mozilla.fenix.perf.StartupTimelineStateMachine.StartupDestination.APP_LINK import org.mozilla.fenix.perf.StartupTimelineStateMachine.StartupDestination.HOMESCREEN import org.mozilla.fenix.perf.StartupTimelineStateMachine.StartupState diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt index 3d2233023..0c3cd8bb2 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt @@ -6,7 +6,7 @@ package org.mozilla.fenix.perf import androidx.annotation.UiThread import org.mozilla.fenix.HomeActivity -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.TopSiteItemViewHolder +import org.mozilla.fenix.home.topsites.TopSiteItemViewHolder import org.mozilla.fenix.perf.StartupTimeline.onApplicationInit import org.mozilla.fenix.perf.StartupTimelineStateMachine.StartupActivity import org.mozilla.fenix.perf.StartupTimelineStateMachine.StartupDestination diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt index 7ab9ea2c0..ddc575173 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabViewHolder.kt @@ -17,7 +17,7 @@ import org.mozilla.fenix.databinding.InactiveTabListItemBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.loadIntoView import org.mozilla.fenix.ext.toShortUrl -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.dpToPx +import org.mozilla.fenix.home.topsites.dpToPx import org.mozilla.fenix.tabstray.TabsTrayInteractor import org.mozilla.fenix.tabstray.browser.AutoCloseInterval.Manual import org.mozilla.fenix.tabstray.browser.AutoCloseInterval.OneDay diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupListAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupListAdapter.kt index a6fb3f28d..15dfdf58e 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupListAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupListAdapter.kt @@ -22,7 +22,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.databinding.TabTrayGridItemBinding import org.mozilla.fenix.databinding.TabTrayItemBinding import org.mozilla.fenix.ext.components -import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.dpToPx +import org.mozilla.fenix.home.topsites.dpToPx import org.mozilla.fenix.selection.SelectionHolder import org.mozilla.fenix.tabstray.TabsTrayStore import org.mozilla.fenix.tabstray.ext.MIN_COLUMN_WIDTH_DP diff --git a/app/src/main/res/layout/component_top_sites_pager.xml b/app/src/main/res/layout/component_top_sites_pager.xml index bacf84f25..b806c28e5 100644 --- a/app/src/main/res/layout/component_top_sites_pager.xml +++ b/app/src/main/res/layout/component_top_sites_pager.xml @@ -14,7 +14,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - Date: Tue, 21 Sep 2021 16:43:38 -0700 Subject: [PATCH 013/563] Closes #21424: add marker for StrictMode.resetAfter. This helps identify file IO. Unfortunately, with this marker, it's difficult to separate code we own from code we don't own. However, I wasn't sure what the best implementation would be to address that (e.g. ideally, we would ignore violations in code we don't own rather than annotate the markers) so I thought we can land it this simple way and improve it incrementally. --- .../mozilla/fenix/perf/StrictModeManager.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt b/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt index 0878a2651..1068f40eb 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt @@ -113,6 +113,18 @@ class StrictModeManager( * @return the value returned by [functionBlock]. */ fun resetAfter(policy: StrictMode.ThreadPolicy, functionBlock: () -> R): R { + fun instrumentedFunctionBlock(): R { + val startProfilerTime = components.core.engine.profiler?.getProfilerTime() + + val returnValue = functionBlock() + + if (mainLooper.thread === Thread.currentThread()) { // markers only supported on main thread. + components.core.engine.profiler?.addMarker("StrictMode.resetAfter", startProfilerTime) + } + + return returnValue + } + // Calling resetAfter takes 1-2ms (unknown device) so we only execute it if StrictMode can // actually be enabled. https://github.com/mozilla-mobile/fenix/issues/11617 return if (isEnabledByBuildConfig) { @@ -122,15 +134,11 @@ class StrictModeManager( val suppressionCount = suppressionCount.incrementAndGet() // We log so that devs are more likely to notice that we're suppressing StrictMode violations. - // We add profiler markers so that the perf team can easily identify IO locations in profiles. logger.warn("StrictMode violation suppressed: #$suppressionCount") - if (Thread.currentThread() == mainLooper.thread) { // markers only supported on main thread. - components.core.engine.profiler?.addMarker("StrictMode.suppression", "Count: $suppressionCount") - } - policy.resetAfter(functionBlock) + policy.resetAfter(::instrumentedFunctionBlock) } else { - functionBlock() + instrumentedFunctionBlock() } } From 507801e5d5e3d7697f81d951d2cdff268ceff044 Mon Sep 17 00:00:00 2001 From: Mugurell Date: Wed, 6 Oct 2021 09:06:05 +0300 Subject: [PATCH 014/563] For #21623 - Pocket recommended stories telemetry --- app/metrics.yaml | 85 +++++++++++ .../mozilla/fenix/components/metrics/Event.kt | 30 ++++ .../components/metrics/GleanMetricsService.kt | 17 +++ .../org/mozilla/fenix/home/HomeFragment.kt | 3 +- .../SessionControlInteractor.kt | 18 ++- .../pocket/PocketStoriesComposables.kt | 34 +++-- .../pocket/PocketStoriesController.kt | 67 +++++++-- .../pocket/PocketStoriesInteractor.kt | 31 +++- .../pocket/PocketStoriesViewHolder.kt | 19 ++- .../home/SessionControlInteractorTest.kt | 37 ++++- .../DefaultPocketStoriesControllerTest.kt | 142 +++++++++++++++--- 11 files changed, 414 insertions(+), 69 deletions(-) diff --git a/app/metrics.yaml b/app/metrics.yaml index 4442b0ef9..58653aa4a 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -3704,6 +3704,91 @@ pocket: notification_emails: - android-probes@mozilla.com expires: "2022-02-01" + home_recs_shown: + type: event + description: | + The Pocket recommended stories are shown on the home screen. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21593 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21625#issuecomment-936745506 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-10-01" + home_recs_story_clicked: + type: event + description: | + User tapped a Pocket recommended story to be opened. + extra_keys: + times_shown: + description: | + How many times was this story shown, including current. + position: + description: | + Position of the clicked story in the list shown. + Uses the [row x column] matrix notation. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21593 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21625#issuecomment-936745506 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-10-01" + home_recs_category_clicked: + type: event + description: | + User tapped a Pocket stories category to filter stories. + extra_keys: + category_name: + description: | + Pocket set topic name representing the just clicked category. + selected_total: + description: | + How many categories were selected before this being tapped. + new_state: + description: | + Category's new state after being tapped. + Possible values: [selected], [deselected]. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21593 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21625#issuecomment-936745506 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-10-01" + home_recs_discover_clicked: + type: event + description: | + User tapped the "Discover more" tile to open a new tab + for more Pocket stories. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21593 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21625#issuecomment-936745506 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-10-01" + home_recs_learn_more_clicked: + type: event + description: | + User tapped "Learn more" to open a new tab for Pocket. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/21593 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/21625#issuecomment-936745506 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: "2022-10-01" first_session: campaign: diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt index 6b1262f7e..7cac6214d 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt @@ -19,6 +19,7 @@ import org.mozilla.fenix.GleanMetrics.ErrorPage import org.mozilla.fenix.GleanMetrics.Events import org.mozilla.fenix.GleanMetrics.Logins import org.mozilla.fenix.GleanMetrics.Onboarding +import org.mozilla.fenix.GleanMetrics.Pocket import org.mozilla.fenix.GleanMetrics.ProgressiveWebApp import org.mozilla.fenix.GleanMetrics.SearchShortcuts import org.mozilla.fenix.GleanMetrics.TabsTray @@ -127,6 +128,35 @@ sealed class Event { object WhatsNewTapped : Event() object PocketTopSiteClicked : Event() object PocketTopSiteRemoved : Event() + object PocketHomeRecsShown : Event() + object PocketHomeRecsDiscoverMoreClicked : Event() + object PocketHomeRecsLearnMoreClicked : Event() + data class PocketHomeRecsStoryClicked( + val timesShown: Long, + val storyPosition: Pair, + ) : Event() { + override val extras: Map + get() = mapOf( + Pocket.homeRecsStoryClickedKeys.timesShown to timesShown.toString(), + Pocket.homeRecsStoryClickedKeys.position to "${storyPosition.first}x${storyPosition.second}" + ) + } + + data class PocketHomeRecsCategoryClicked( + val categoryname: String, + val previousSelectedCategoriesTotal: Int, + val isSelectedNextState: Boolean + ) : Event() { + override val extras: Map + get() = mapOf( + Pocket.homeRecsCategoryClickedKeys.categoryName to categoryname, + Pocket.homeRecsCategoryClickedKeys.selectedTotal to previousSelectedCategoriesTotal.toString(), + Pocket.homeRecsCategoryClickedKeys.newState to when (isSelectedNextState) { + true -> "selected" + false -> "deselected" + } + ) + } object FennecToFenixMigrated : Event() object AddonsOpenInSettings : Event() object VoiceSearchTapped : Event() diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt index b13afb8d4..8b96a0728 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt @@ -493,6 +493,23 @@ private val Event.wrapper: EventWrapper<*>? is Event.PocketTopSiteRemoved -> EventWrapper( { Pocket.pocketTopSiteRemoved.record(it) } ) + is Event.PocketHomeRecsShown -> EventWrapper( + { Pocket.homeRecsShown.record(it) } + ) + is Event.PocketHomeRecsLearnMoreClicked -> EventWrapper( + { Pocket.homeRecsLearnMoreClicked.record(it) } + ) + is Event.PocketHomeRecsDiscoverMoreClicked -> EventWrapper( + { Pocket.homeRecsDiscoverClicked.record(it) } + ) + is Event.PocketHomeRecsStoryClicked -> EventWrapper( + { Pocket.homeRecsStoryClicked.record(it) }, + { Pocket.homeRecsStoryClickedKeys.valueOf(it) } + ) + is Event.PocketHomeRecsCategoryClicked -> EventWrapper( + { Pocket.homeRecsCategoryClicked.record(it) }, + { Pocket.homeRecsCategoryClickedKeys.valueOf(it) } + ) is Event.DarkThemeSelected -> EventWrapper( { AppTheme.darkThemeSelected.record(it) }, { AppTheme.darkThemeSelectedKeys.valueOf(it) } diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index b20528d8f..70d635b00 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -355,7 +355,8 @@ class HomeFragment : Fragment() { pocketStoriesController = DefaultPocketStoriesController( homeActivity = activity, homeStore = homeFragmentStore, - navController = findNavController() + navController = findNavController(), + metrics = requireComponents.analytics.metrics ) ) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt index 2963da596..78aa0b037 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt @@ -391,15 +391,23 @@ class SessionControlInteractor( controller.handleCustomizeHomeTapped() } - override fun onCategoryClick(categoryClicked: PocketRecommendedStoriesCategory) { + override fun onStoriesShown(storiesShown: List) { + pocketStoriesController.handleStoriesShown(storiesShown) + } + + override fun onCategoryClicked(categoryClicked: PocketRecommendedStoriesCategory) { pocketStoriesController.handleCategoryClick(categoryClicked) } - override fun onStoriesShown(storiesShown: List) { - pocketStoriesController.handleStoriesShown(storiesShown) + override fun onStoryClicked(storyClicked: PocketRecommendedStory, storyPosition: Pair) { + pocketStoriesController.handleStoryClicked(storyClicked, storyPosition) + } + + override fun onLearnMoreClicked(link: String) { + pocketStoriesController.handleLearnMoreClicked(link) } - override fun onExternalLinkClicked(link: String) { - pocketStoriesController.handleExternalLinkClick(link) + override fun onDiscoverMoreClicked(link: String) { + pocketStoriesController.handleDiscoverMoreClicked(link) } } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt index 8860ffb9e..b059f6c8b 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesComposables.kt @@ -19,7 +19,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Icon import androidx.compose.material.Text @@ -107,14 +107,15 @@ fun PocketStory( * @param stories The list of [PocketRecommendedStory]ies to be displayed. Expect a list with 8 items. * @param contentPadding Dimension for padding the content after it has been clipped. * This space will be used for shadows and also content rendering when the list is scrolled. - * @param onExternalLinkClicked Callback for when the user taps an element which contains an - * external link for where user can go for more recommendations. + * @param onStoryClicked Callback for when the user taps on a recommended story. + * @param onDiscoverMoreClicked Callback for when the user taps an element which contains an */ @Composable fun PocketStories( @PreviewParameter(PocketStoryProvider::class) stories: List, contentPadding: Dp, - onExternalLinkClicked: (String) -> Unit + onStoryClicked: (PocketRecommendedStory, Pair) -> Unit, + onDiscoverMoreClicked: (String) -> Unit ) { // Show stories in at most 3 rows but on any number of columns depending on the data received. val maxRowsNo = 3 @@ -129,20 +130,20 @@ fun PocketStories( flingBehavior = flingBehavior, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - items(storiesToShow) { columnItems -> + itemsIndexed(storiesToShow) { columnIndex, columnItems -> Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - columnItems.forEach { story -> + columnItems.forEachIndexed { rowIndex, story -> if (story == placeholderStory) { ListItemTabLargePlaceholder(stringResource(R.string.pocket_stories_placeholder_text)) { - onExternalLinkClicked("https://getpocket.com/explore?$POCKET_FEATURE_UTM_KEY_VALUE") + onDiscoverMoreClicked("https://getpocket.com/explore?$POCKET_FEATURE_UTM_KEY_VALUE") } } else { - val uri = Uri.parse(story.url) - .buildUpon() - .appendQueryParameter(URI_PARAM_UTM_KEY, POCKET_STORIES_UTM_VALUE) - .build().toString() PocketStory(story) { - onExternalLinkClicked(uri) + val uri = Uri.parse(story.url) + .buildUpon() + .appendQueryParameter(URI_PARAM_UTM_KEY, POCKET_STORIES_UTM_VALUE) + .build().toString() + onStoryClicked(it.copy(url = uri), rowIndex to columnIndex) } } } @@ -184,13 +185,13 @@ fun PocketStoriesCategories( * Pocket feature section title. * Shows a default text about Pocket and offers a external link to learn more. * - * @param onExternalLinkClicked Callback invoked when the user clicks the "Learn more" link. + * @param onLearnMoreClicked Callback invoked when the user clicks the "Learn more" link. * Contains the full URL for where the user should be navigated to. * @param modifier [Modifier] to be applied to the layout. */ @Composable fun PoweredByPocketHeader( - onExternalLinkClicked: (String) -> Unit, + onLearnMoreClicked: (String) -> Unit, modifier: Modifier = Modifier ) { val color = when (isSystemInDarkTheme()) { @@ -231,7 +232,7 @@ fun PoweredByPocketHeader( ) ClickableSubstringLink(text, color, linkStartIndex, linkEndIndex) { - onExternalLinkClicked("https://www.mozilla.org/en-US/firefox/pocket/?$POCKET_FEATURE_UTM_KEY_VALUE") + onLearnMoreClicked("https://www.mozilla.org/en-US/firefox/pocket/?$POCKET_FEATURE_UTM_KEY_VALUE") } } } @@ -247,7 +248,8 @@ private fun PocketStoriesComposablesPreview() { PocketStories( stories = getFakePocketStories(8), contentPadding = 0.dp, - onExternalLinkClicked = { } + onStoryClicked = { _, _ -> }, + onDiscoverMoreClicked = { } ) Spacer(Modifier.height(10.dp)) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesController.kt index 627415e8b..708f3136b 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesController.kt @@ -13,11 +13,20 @@ import mozilla.components.service.pocket.PocketRecommendedStory import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.components.metrics.MetricController /** * Contract for how all user interactions with the Pocket recommended stories feature are to be handled. */ interface PocketStoriesController { + /** + * Callback to decide what should happen as an effect of a new list of stories being shown. + * + * @param storiesShown the new list of [PocketRecommendedStory]es shown to the user. + */ + fun handleStoriesShown(storiesShown: List) + /** * Callback allowing to handle a specific [PocketRecommendedStoriesCategory] being clicked by the user. * @@ -26,18 +35,26 @@ interface PocketStoriesController { fun handleCategoryClick(categoryClicked: PocketRecommendedStoriesCategory): Unit /** - * Callback to decide what should happen as an effect of a new list of stories being shown. + * Callback for when the user clicks on a specific story. * - * @param storiesShown the new list of [PocketRecommendedStory]es shown to the user. + * @param storyClicked The just clicked [PocketRecommendedStory] URL. + * @param storyPosition `row x column` matrix representing the grid position of the clicked story. */ - fun handleStoriesShown(storiesShown: List) + fun handleStoryClicked(storyClicked: PocketRecommendedStory, storyPosition: Pair) /** - * Callback for when the an external link is clicked. + * Callback for when the "Learn more" link is clicked. * * @param link URL clicked. */ - fun handleExternalLinkClick(link: String) + fun handleLearnMoreClicked(link: String) + + /** + * Callback for when the "Discover more" link is clicked. + * + * @param link URL clicked. + */ + fun handleDiscoverMoreClicked(link: String) } /** @@ -50,14 +67,27 @@ interface PocketStoriesController { internal class DefaultPocketStoriesController( private val homeActivity: HomeActivity, private val homeStore: HomeFragmentStore, - private val navController: NavController + private val navController: NavController, + private val metrics: MetricController ) : PocketStoriesController { + override fun handleStoriesShown(storiesShown: List) { + homeStore.dispatch(HomeFragmentAction.PocketStoriesShown(storiesShown)) + metrics.track(Event.PocketHomeRecsShown) + } + override fun handleCategoryClick(categoryClicked: PocketRecommendedStoriesCategory) { val initialCategoriesSelections = homeStore.state.pocketStoriesCategoriesSelections // First check whether the category is clicked to be deselected. if (initialCategoriesSelections.map { it.name }.contains(categoryClicked.name)) { homeStore.dispatch(HomeFragmentAction.DeselectPocketStoriesCategory(categoryClicked.name)) + metrics.track( + Event.PocketHomeRecsCategoryClicked( + categoryClicked.name, + initialCategoriesSelections.size, + false + ) + ) return } @@ -75,19 +105,36 @@ internal class DefaultPocketStoriesController( // Finally update the selection. homeStore.dispatch(HomeFragmentAction.SelectPocketStoriesCategory(categoryClicked.name)) + + metrics.track( + Event.PocketHomeRecsCategoryClicked( + categoryClicked.name, + initialCategoriesSelections.size, + true + ) + ) } - override fun handleStoriesShown(storiesShown: List) { - homeStore.dispatch(HomeFragmentAction.PocketStoriesShown(storiesShown)) + override fun handleStoryClicked(storyClicked: PocketRecommendedStory, storyPosition: Pair) { + dismissSearchDialogIfDisplayed() + homeActivity.openToBrowserAndLoad(storyClicked.url, true, BrowserDirection.FromHome) + metrics.track(Event.PocketHomeRecsStoryClicked(storyClicked.timesShown.inc(), storyPosition)) + } + + override fun handleLearnMoreClicked(link: String) { + dismissSearchDialogIfDisplayed() + homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) + metrics.track(Event.PocketHomeRecsLearnMoreClicked) } - override fun handleExternalLinkClick(link: String) { + override fun handleDiscoverMoreClicked(link: String) { dismissSearchDialogIfDisplayed() homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) + metrics.track(Event.PocketHomeRecsDiscoverMoreClicked) } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - fun dismissSearchDialogIfDisplayed() { + internal fun dismissSearchDialogIfDisplayed() { if (navController.currentDestination?.id == R.id.searchDialogFragment) { navController.navigateUp() } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesInteractor.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesInteractor.kt index 67dab5137..db814fc84 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesInteractor.kt @@ -11,23 +11,38 @@ import mozilla.components.service.pocket.PocketRecommendedStory */ interface PocketStoriesInteractor { /** - * Callback for when the user clicked a specific category. + * Callback for then new stories are shown to the user. * - * @param categoryClicked the just clicked [PocketRecommendedStoriesCategory]. + * @param storiesShown The new list of [PocketRecommendedStory]es shown to the user. */ - fun onCategoryClick(categoryClicked: PocketRecommendedStoriesCategory) + fun onStoriesShown(storiesShown: List) /** - * Callback for then new stories are shown to the user. + * Callback for when the user clicks a specific category. * - * @param storiesShown the new list of [PocketRecommendedStory]es shown to the user. + * @param categoryClicked The just clicked [PocketRecommendedStoriesCategory]. */ - fun onStoriesShown(storiesShown: List) + fun onCategoryClicked(categoryClicked: PocketRecommendedStoriesCategory) + + /** + * Callback for when the user clicks on a specific story. + * + * @param storyClicked The just clicked [PocketRecommendedStory] URL. + * @param storyPosition `row x column` matrix representing the grid position of the clicked story. + */ + fun onStoryClicked(storyClicked: PocketRecommendedStory, storyPosition: Pair) + + /** + * Callback for when the user clicks the "Learn more" link. + * + * @param link URL clicked. + */ + fun onLearnMoreClicked(link: String) /** - * Callback for when the user clicks an external link. + * Callback for when the user clicks the "Discover more" link. * * @param link URL clicked. */ - fun onExternalLinkClicked(link: String) + fun onDiscoverMoreClicked(link: String) } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt index 116ff8ff8..358e269e7 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt @@ -52,8 +52,10 @@ class PocketStoriesViewHolder( PocketStories( store, interactor::onStoriesShown, - interactor::onCategoryClick, - interactor::onExternalLinkClicked, + interactor::onStoryClicked, + interactor::onCategoryClicked, + interactor::onDiscoverMoreClicked, + interactor::onLearnMoreClicked, with(composeView.resources) { getDimensionPixelSize(R.dimen.home_item_horizontal_margin) / displayMetrics.density } @@ -68,11 +70,14 @@ class PocketStoriesViewHolder( } @Composable +@Suppress("LongParameterList") fun PocketStories( store: HomeFragmentStore, onStoriesShown: (List) -> Unit, - onCategoryClick: (PocketRecommendedStoriesCategory) -> Unit, - onExternalLinkClicked: (String) -> Unit, + onStoryClicked: (PocketRecommendedStory, Pair) -> Unit, + onCategoryClicked: (PocketRecommendedStoriesCategory) -> Unit, + onDiscoverMoreClicked: (String) -> Unit, + onLearnMoreClicked: (String) -> Unit, @Dimension horizontalPadding: Float = 0f ) { val stories = store @@ -102,7 +107,7 @@ fun PocketStories( Spacer(Modifier.height(17.dp)) - PocketStories(stories ?: emptyList(), horizontalPadding.dp, onExternalLinkClicked) + PocketStories(stories ?: emptyList(), horizontalPadding.dp, onStoryClicked, onDiscoverMoreClicked) Spacer(Modifier.height(24.dp)) @@ -118,7 +123,7 @@ fun PocketStories( PocketStoriesCategories( categories = categories ?: emptyList(), selections = categoriesSelections ?: emptyList(), - onCategoryClick = onCategoryClick, + onCategoryClick = onCategoryClicked, modifier = Modifier .fillMaxWidth() .padding(horizontal = horizontalPadding.dp) @@ -127,7 +132,7 @@ fun PocketStories( Spacer(Modifier.height(24.dp)) PoweredByPocketHeader( - onExternalLinkClicked, + onLearnMoreClicked, modifier = Modifier .fillMaxWidth() .padding(horizontal = horizontalPadding.dp) diff --git a/app/src/test/java/org/mozilla/fenix/home/SessionControlInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/home/SessionControlInteractorTest.kt index 7be805ce9..9bee29a0e 100644 --- a/app/src/test/java/org/mozilla/fenix/home/SessionControlInteractorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/SessionControlInteractorTest.kt @@ -10,6 +10,7 @@ import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.feature.tab.collections.Tab import mozilla.components.feature.tab.collections.TabCollection +import mozilla.components.service.pocket.PocketRecommendedStory import org.junit.Before import org.junit.Test import org.mozilla.fenix.browser.browsingmode.BrowsingMode @@ -213,21 +214,49 @@ class SessionControlInteractorTest { verify { controller.handlePrivateModeButtonClicked(newMode, hasBeenOnboarded) } } + @Test + fun `GIVEN a PocketStoriesInteractor WHEN stories are shown THEN handle it in a PocketStoriesController`() { + val shownStories: List = mockk() + + interactor.onStoriesShown(shownStories) + + verify { pocketStoriesController.handleStoriesShown(shownStories) } + } + @Test fun `GIVEN a PocketStoriesInteractor WHEN a category is clicked THEN handle it in a PocketStoriesController`() { val clickedCategory: PocketRecommendedStoriesCategory = mockk() - interactor.onCategoryClick(clickedCategory) + interactor.onCategoryClicked(clickedCategory) verify { pocketStoriesController.handleCategoryClick(clickedCategory) } } @Test - fun `GIVEN a PocketStoriesInteractor WHEN an external link is clicked THEN handle it in a PocketStoriesController`() { + fun `GIVEN a PocketStoriesInteractor WHEN a story is clicked THEN handle it in a PocketStoriesController`() { + val clickedStory: PocketRecommendedStory = mockk() + val storyGridLocation = 1 to 2 + + interactor.onStoryClicked(clickedStory, storyGridLocation) + + verify { pocketStoriesController.handleStoryClicked(clickedStory, storyGridLocation) } + } + + @Test + fun `GIVEN a PocketStoriesInteractor WHEN discover more clicked THEN handle it in a PocketStoriesController`() { + val link = "http://getpocket.com/explore" + + interactor.onDiscoverMoreClicked(link) + + verify { pocketStoriesController.handleDiscoverMoreClicked(link) } + } + + @Test + fun `GIVEN a PocketStoriesInteractor WHEN learn more clicked THEN handle it in a PocketStoriesController`() { val link = "https://www.mozilla.org/en-US/firefox/pocket/" - interactor.onExternalLinkClicked(link) + interactor.onLearnMoreClicked(link) - verify { pocketStoriesController.handleExternalLinkClick(link) } + verify { pocketStoriesController.handleLearnMoreClicked(link) } } } diff --git a/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/DefaultPocketStoriesControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/DefaultPocketStoriesControllerTest.kt index ad4effd8f..9185ac21d 100644 --- a/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/DefaultPocketStoriesControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/DefaultPocketStoriesControllerTest.kt @@ -9,18 +9,23 @@ import io.mockk.every import io.mockk.mockk import io.mockk.spyk import io.mockk.verify +import io.mockk.verifyOrder import mozilla.components.service.pocket.PocketRecommendedStory import org.junit.Test import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.home.HomeFragmentAction import org.mozilla.fenix.home.HomeFragmentState import org.mozilla.fenix.home.HomeFragmentStore class DefaultPocketStoriesControllerTest { + val metrics: MetricController = mockk(relaxed = true) + @Test - fun `GIVEN a category is selected WHEN that same category is clicked THEN deselect it`() { + fun `GIVEN a category is selected WHEN that same category is clicked THEN deselect it and record telemetry`() { val category1 = PocketRecommendedStoriesCategory("cat1", emptyList()) val category2 = PocketRecommendedStoriesCategory("cat2", emptyList()) val selections = listOf(PocketRecommendedStoriesSelectedCategory(category2.name)) @@ -32,17 +37,21 @@ class DefaultPocketStoriesControllerTest { ) ) ) - val controller = DefaultPocketStoriesController(mockk(), store, mockk()) + val controller = DefaultPocketStoriesController(mockk(), store, mockk(), metrics) controller.handleCategoryClick(category1) verify(exactly = 0) { store.dispatch(HomeFragmentAction.DeselectPocketStoriesCategory(category1.name)) } + verify { store.dispatch(HomeFragmentAction.SelectPocketStoriesCategory(category1.name)) } + verify { metrics.track(Event.PocketHomeRecsCategoryClicked(category1.name, 1, true)) } controller.handleCategoryClick(category2) + verify(exactly = 0) { store.dispatch(HomeFragmentAction.SelectPocketStoriesCategory(category2.name)) } verify { store.dispatch(HomeFragmentAction.DeselectPocketStoriesCategory(category2.name)) } + verify { metrics.track(Event.PocketHomeRecsCategoryClicked(category2.name, 2, false)) } } @Test - fun `GIVEN 8 categories are selected WHEN when a new one is clicked THEN the oldest selected is deselected before selecting the new one`() { + fun `GIVEN 8 categories are selected WHEN when a new one is clicked THEN the oldest selected is deselected before selecting the new one and record telemetry`() { val category1 = PocketRecommendedStoriesSelectedCategory(name = "cat1", selectionTimestamp = 111) val category2 = PocketRecommendedStoriesSelectedCategory(name = "cat2", selectionTimestamp = 222) val category3 = PocketRecommendedStoriesSelectedCategory(name = "cat3", selectionTimestamp = 333) @@ -61,16 +70,17 @@ class DefaultPocketStoriesControllerTest { ) ) ) - val controller = DefaultPocketStoriesController(mockk(), store, mockk()) + val controller = DefaultPocketStoriesController(mockk(), store, mockk(), metrics) controller.handleCategoryClick(PocketRecommendedStoriesCategory(newSelectedCategory.name)) verify { store.dispatch(HomeFragmentAction.DeselectPocketStoriesCategory(oldestSelectedCategory.name)) } verify { store.dispatch(HomeFragmentAction.SelectPocketStoriesCategory(newSelectedCategory.name)) } + verify { metrics.track(Event.PocketHomeRecsCategoryClicked(newSelectedCategory.name, 8, true)) } } @Test - fun `GIVEN fewer than 8 categories are selected WHEN when a new one is clicked THEN don't deselect anything but select the newly clicked category`() { + fun `GIVEN fewer than 8 categories are selected WHEN when a new one is clicked THEN don't deselect anything but select the newly clicked category and record telemetry`() { val category1 = PocketRecommendedStoriesSelectedCategory(name = "cat1", selectionTimestamp = 111) val category2 = PocketRecommendedStoriesSelectedCategory(name = "cat2", selectionTimestamp = 222) val category3 = PocketRecommendedStoriesSelectedCategory(name = "cat3", selectionTimestamp = 333) @@ -87,50 +97,146 @@ class DefaultPocketStoriesControllerTest { ) ) ) - val controller = DefaultPocketStoriesController(mockk(), store, mockk()) + val newSelectedCategoryName = "newSelectedCategory" + val controller = DefaultPocketStoriesController(mockk(), store, mockk(), metrics) - controller.handleCategoryClick(PocketRecommendedStoriesCategory("newSelectedCategory")) + controller.handleCategoryClick(PocketRecommendedStoriesCategory(newSelectedCategoryName)) verify(exactly = 0) { store.dispatch(HomeFragmentAction.DeselectPocketStoriesCategory(oldestSelectedCategory.name)) } - verify { store.dispatch(HomeFragmentAction.SelectPocketStoriesCategory("newSelectedCategory")) } + verify { store.dispatch(HomeFragmentAction.SelectPocketStoriesCategory(newSelectedCategoryName)) } + verify { metrics.track(Event.PocketHomeRecsCategoryClicked(newSelectedCategoryName, 7, true)) } } @Test - fun `WHEN new stories are shown THEN update the State`() { + fun `WHEN new stories are shown THEN update the State and record telemetry`() { val store = spyk(HomeFragmentStore()) - val controller = DefaultPocketStoriesController(mockk(), store, mockk()) + val controller = DefaultPocketStoriesController(mockk(), store, mockk(), metrics) val storiesShown: List = mockk() controller.handleStoriesShown(storiesShown) verify { store.dispatch(HomeFragmentAction.PocketStoriesShown(storiesShown)) } + verify { metrics.track(Event.PocketHomeRecsShown) } } @Test - fun `WHEN an external link is clicked THEN link is opened`() { - val link = "https://www.mozilla.org/en-US/firefox/pocket/" + fun `WHEN a story is clicked then open that story's url using HomeActivity and record telemetry`() { + val story = PocketRecommendedStory( + title = "", + url = "testLink", + imageUrl = "", + publisher = "", + category = "", + timeToRead = 0, + timesShown = 123 + ) + val homeActivity: HomeActivity = mockk(relaxed = true) + val controller = DefaultPocketStoriesController(homeActivity, mockk(), mockk(relaxed = true), metrics) + + controller.handleStoryClicked(story, 1 to 2) + + verify { homeActivity.openToBrowserAndLoad(story.url, true, BrowserDirection.FromHome) } + metrics.track(Event.PocketHomeRecsStoryClicked(story.timesShown, 1 to 2)) + } + + @Test + fun `WHEN discover more is clicked then open that using HomeActivity and record telemetry`() { + val link = "http://getpocket.com/explore" val homeActivity: HomeActivity = mockk(relaxed = true) - val controller = DefaultPocketStoriesController(homeActivity, mockk(), mockk(relaxed = true)) + val controller = DefaultPocketStoriesController(homeActivity, mockk(), mockk(relaxed = true), metrics) - controller.handleExternalLinkClick(link) + controller.handleDiscoverMoreClicked(link) verify { homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) } + metrics.track(Event.PocketHomeRecsDiscoverMoreClicked) } @Test - fun `WHEN an external link is clicked THEN link is opened and search dismissed`() { + fun `WHEN learn more is clicked then open that using HomeActivity and record telemetry`() { val link = "https://www.mozilla.org/en-US/firefox/pocket/" val homeActivity: HomeActivity = mockk(relaxed = true) + val controller = DefaultPocketStoriesController(homeActivity, mockk(), mockk(relaxed = true), metrics) + + controller.handleLearnMoreClicked(link) + + verify { homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) } + metrics.track(Event.PocketHomeRecsLearnMoreClicked) + } + + @Test + fun `WHEN a story is clicked THEN search is dismissed and then its link opened`() { + val story = PocketRecommendedStory("", "url", "", "", "", 0, 0) + val homeActivity: HomeActivity = mockk(relaxed = true) val navController: NavController = mockk(relaxed = true) + every { navController.currentDestination } returns mockk { + every { id } returns R.id.searchDialogFragment + } + val controller = DefaultPocketStoriesController(homeActivity, mockk(), navController, metrics) + + controller.handleStoryClicked(story, 1 to 2) + verifyOrder { + navController.navigateUp() + homeActivity.openToBrowserAndLoad(story.url, true, BrowserDirection.FromHome) + } + } + + @Test + fun `WHEN discover more is clicked THEN search is dismissed and then its link opened`() { + val link = "https://discoverMore.link" + val homeActivity: HomeActivity = mockk(relaxed = true) + val navController: NavController = mockk(relaxed = true) every { navController.currentDestination } returns mockk { every { id } returns R.id.searchDialogFragment } + val controller = DefaultPocketStoriesController(homeActivity, mockk(), navController, metrics) - val controller = DefaultPocketStoriesController(homeActivity, mockk(), navController) - controller.handleExternalLinkClick(link) + controller.handleDiscoverMoreClicked(link) + + verifyOrder { + navController.navigateUp() + homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) + } + } + + @Test + fun `WHEN learn more link is clicked THEN search is dismissed and then that link is opened`() { + val link = "https://learnMore.link" + val homeActivity: HomeActivity = mockk(relaxed = true) + val navController: NavController = mockk(relaxed = true) + every { navController.currentDestination } returns mockk { + every { id } returns R.id.searchDialogFragment + } + val controller = DefaultPocketStoriesController(homeActivity, mockk(), navController, metrics) + + controller.handleLearnMoreClicked(link) + + verifyOrder { + navController.navigateUp() + homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) + } + } + + @Test + fun `GIVEN search dialog is currently focused WHEN dismissSearchDialogIfDisplayed is called THEN close the search dialog`() { + val navController: NavController = mockk(relaxed = true) + every { navController.currentDestination } returns mockk { + every { id } returns R.id.searchDialogFragment + } + val controller = DefaultPocketStoriesController(mockk(), mockk(), navController, mockk()) + + controller.dismissSearchDialogIfDisplayed() - verify { homeActivity.openToBrowserAndLoad(link, true, BrowserDirection.FromHome) } verify { navController.navigateUp() } } + + @Test + fun `GIVEN search dialog is not currently focused WHEN dismissSearchDialogIfDisplayed is called THEN do nothing`() { + val navController: NavController = mockk(relaxed = true) + val controller = DefaultPocketStoriesController(mockk(), mockk(), navController, mockk()) + + controller.dismissSearchDialogIfDisplayed() + + verify(exactly = 0) { navController.navigateUp() } + } } From 5843fafbb6c40071fafdb97a2d8132e89cb10493 Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Thu, 7 Oct 2021 10:48:29 -0400 Subject: [PATCH 015/563] For #21765 only activate pocket by default for the right audience --- .../main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt b/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt index 79042b18b..8636339c8 100644 --- a/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt +++ b/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt @@ -62,7 +62,7 @@ class NimbusFeatures(private val context: Context) { */ fun toMap(context: Context): Map { return values().associate { section -> - val channelDefault = if (section == pocket) { + val channelDefault = if (section == pocket && Config.channel.isNightlyOrDebug) { FeatureFlags.isPocketRecommendationsFeatureEnabled(context) } else { Config.channel.isNightlyOrDebug From 7a08e7acddf1762877a72cf8cfe9580ecb6d270b Mon Sep 17 00:00:00 2001 From: gmierz Date: Wed, 6 Oct 2021 15:00:11 -0400 Subject: [PATCH 016/563] Update visual-metrics script to the latest version. --- .../visual-metrics/run-visual-metrics.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/taskcluster/docker/visual-metrics/run-visual-metrics.py b/taskcluster/docker/visual-metrics/run-visual-metrics.py index 2593a0877..7db40a8bc 100755 --- a/taskcluster/docker/visual-metrics/run-visual-metrics.py +++ b/taskcluster/docker/visual-metrics/run-visual-metrics.py @@ -43,6 +43,9 @@ class Job: #: A unique number for the job. count = attr.ib(type=int) + #: The tags for this job. + tags = attr.ib(type=str) + #: The extra options for this job. extra_options = attr.ib(type=str) @@ -63,6 +66,7 @@ JOB_SCHEMA = Schema( { Required("test_name"): str, Required("browsertime_json_path"): str, + Required("tags"): [str], Required("extra_options"): [str], Required("accept_zero_vismet"): bool, } @@ -149,7 +153,7 @@ def run_command(log, cmd, job_count): return rc, res -def append_result(log, suites, test_name, name, result, extra_options): +def append_result(log, suites, test_name, name, result, tags, extra_options): """Appends a ``name`` metrics result in the ``test_name`` suite. Args: @@ -177,7 +181,7 @@ def append_result(log, suites, test_name, name, result, extra_options): test_name, { "name": orig_test_name, - "tags": extra_options + ["visual"], + "tags": extra_options + tags + ["visual"], "subtests": {}, "extraOptions": extra_options, }, @@ -320,9 +324,13 @@ def main(log, args): for site in browsertime_json: for video in site["files"]["video"]: count += 1 + name = job["test_name"] + if "alias" in site["info"] and site["info"]["alias"].strip() != "": + name = "%s.%s" % (name, site["info"]["alias"]) jobs.append( Job( - test_name=job["test_name"], + test_name=name, + tags=job["tags"], extra_options=len(job["extra_options"]) > 0 and job["extra_options"] or jobs_json["extra_options"], @@ -359,7 +367,13 @@ def main(log, args): else: for name, value in res.items(): append_result( - log, suites, job.test_name, name, value, job.extra_options + log, + suites, + job.test_name, + name, + value, + job.tags, + job.extra_options, ) suites = [get_suite(suite) for suite in suites.values()] From f41857e5e7b093d34574463712bdd7a2b49faadd Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Thu, 7 Oct 2021 15:39:42 +0000 Subject: [PATCH 017/563] Update Android Components version to 95.0.20211006190137. --- buildSrc/src/main/java/AndroidComponents.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 43ab69898..37984dcbd 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "95.0.20211006143357" + const val VERSION = "95.0.20211006190137" } From a77091dc5b14bb4e64731562c8f1b2885377b6ca Mon Sep 17 00:00:00 2001 From: Rohan Maity Date: Sun, 5 Sep 2021 15:24:22 +0530 Subject: [PATCH 018/563] For #20579: Fix the normal browing tab re-used unexpectedly when open links in private tab enabled or same tab is already avaialble in normal browsing mode --- .../java/org/mozilla/fenix/browser/BaseBrowserFragment.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 19e45b079..3d729fd79 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -1033,10 +1033,6 @@ abstract class BaseBrowserFragment : components.useCases.sessionUseCases.reload() } hideToolbar() - - components.core.store.state.findTabOrCustomTabOrSelectedTab(customTabSessionId)?.let { - updateThemeForSession(it) - } } @CallSuper From 3f9d277566cceed8449c63b19939afba4c8ea104 Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Thu, 7 Oct 2021 16:15:21 -0400 Subject: [PATCH 019/563] Prepare nimbus features default values for release 95 --- .../mozilla/fenix/experiments/NimbusFeatures.kt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt b/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt index 8636339c8..e05542fb5 100644 --- a/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt +++ b/app/src/main/java/org/mozilla/fenix/experiments/NimbusFeatures.kt @@ -6,7 +6,6 @@ package org.mozilla.fenix.experiments import android.content.Context import org.mozilla.experiments.nimbus.mapKeysAsEnums -import org.mozilla.fenix.Config import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.getVariables @@ -51,10 +50,10 @@ class NimbusFeatures(private val context: Context) { @Suppress("EnumNaming") private enum class HomeScreenSection(val default: Boolean) { topSites(true), - recentlySaved(false), - jumpBackIn(false), - pocket(false), - recentExplorations(false); + recentlySaved(true), + jumpBackIn(true), + pocket(true), + recentExplorations(true); companion object { /** @@ -62,12 +61,12 @@ class NimbusFeatures(private val context: Context) { */ fun toMap(context: Context): Map { return values().associate { section -> - val channelDefault = if (section == pocket && Config.channel.isNightlyOrDebug) { + val value = if (section == pocket) { FeatureFlags.isPocketRecommendationsFeatureEnabled(context) } else { - Config.channel.isNightlyOrDebug + section.default } - section to (channelDefault || section.default) + section to value } } } From 1b463a5c1791434f683054a77fdcd232b43ca9fd Mon Sep 17 00:00:00 2001 From: Christian Sadilek Date: Thu, 7 Oct 2021 17:17:42 -0400 Subject: [PATCH 020/563] Enable pocket stories in CA --- app/src/main/java/org/mozilla/fenix/FeatureFlags.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index 165beb782..9d514cc91 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -82,8 +82,9 @@ object FeatureFlags { * Show Pocket recommended stories on home. */ fun isPocketRecommendationsFeatureEnabled(context: Context): Boolean { - return "en-US" == LocaleManager.getCurrentLocale(context) + val langTag = LocaleManager.getCurrentLocale(context) ?.toLanguageTag() ?: getSystemDefault().toLanguageTag() + return listOf("en-US", "en-CA").contains(langTag) } /** From 8c1a64a5e869679d5b05c02a533378e75f326f42 Mon Sep 17 00:00:00 2001 From: Noah Bond Date: Thu, 7 Oct 2021 14:56:14 -0700 Subject: [PATCH 021/563] For #21773 - Updated "customize homepage" button to go to the new Homepage submenu in Settings --- app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt | 2 +- .../fenix/home/sessioncontrol/SessionControlController.kt | 2 +- app/src/main/res/navigation/nav_graph.xml | 7 ++----- .../fenix/home/DefaultSessionControlControllerTest.kt | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index 70d635b00..324ee750a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -881,7 +881,7 @@ class HomeFragment : Fragment() { hideOnboardingIfNeeded() nav( R.id.homeFragment, - HomeFragmentDirections.actionGlobalCustomizationFragment() + HomeFragmentDirections.actionGlobalHomeSettingsFragment() ) } is HomeMenu.Item.SyncAccount -> { diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index 9b956a3dd..edbb31bc5 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -449,7 +449,7 @@ class DefaultSessionControlController( } override fun handleCustomizeHomeTapped() { - val directions = HomeFragmentDirections.actionGlobalCustomizationFragment() + val directions = HomeFragmentDirections.actionGlobalHomeSettingsFragment() navController.nav(R.id.homeFragment, directions) metrics.track(Event.HomeScreenCustomizedHomeClicked) } diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index f77ac80df..e0a1173c7 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -67,8 +67,8 @@ android:id="@+id/action_global_settingsFragment" app:destination="@id/settingsFragment" /> + android:id="@+id/action_global_homeSettingsFragment" + app:destination="@id/homeSettingsFragment" /> @@ -215,9 +215,6 @@ - diff --git a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt index e82204ccc..408bfd935 100644 --- a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt @@ -170,7 +170,7 @@ class DefaultSessionControlControllerTest { verify { navController.navigate( match { - it.actionId == R.id.action_global_customizationFragment + it.actionId == R.id.action_global_homeSettingsFragment }, null ) From 74fd0432900a73b5e79247a2235df72e96c028f3 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Thu, 7 Oct 2021 16:30:06 -0400 Subject: [PATCH 022/563] Issue #21686: Move submitList calls into TabsAdapter Co-authored-by: Roger Yang --- .../tabstray/browser/InactiveTabsAdapter.kt | 4 ---- .../fenix/tabstray/browser/TabGroupAdapter.kt | 4 ---- .../mozilla/fenix/tabstray/browser/TabSorter.kt | 9 --------- .../fenix/tabstray/browser/TabsAdapter.kt | 16 ++-------------- .../AbstractBrowserPageViewHolderTest.kt | 2 -- 5 files changed, 2 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabsAdapter.kt index 49dec1eee..473950a7e 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabsAdapter.kt @@ -105,10 +105,6 @@ class InactiveTabsAdapter( } override fun isTabSelected(tabs: Tabs, position: Int): Boolean = false - override fun onTabsChanged(position: Int, count: Int) = Unit - override fun onTabsInserted(position: Int, count: Int) = Unit - override fun onTabsMoved(fromPosition: Int, toPosition: Int) = Unit - override fun onTabsRemoved(position: Int, count: Int) = Unit private object DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean { diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupAdapter.kt index 1298f85e5..17b000ada 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabGroupAdapter.kt @@ -109,10 +109,6 @@ class TabGroupAdapter( * Not implemented; handled by nested [RecyclerView]. */ override fun isTabSelected(tabs: Tabs, position: Int): Boolean = false - override fun onTabsChanged(position: Int, count: Int) = Unit - override fun onTabsInserted(position: Int, count: Int) = Unit - override fun onTabsMoved(fromPosition: Int, toPosition: Int) = Unit - override fun onTabsRemoved(position: Int, count: Int) = Unit private object DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Group, newItem: Group) = oldItem.title == newItem.title diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt index ddc8aba3e..de9e1232b 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabSorter.kt @@ -46,19 +46,10 @@ class TabSorter( // Normal tabs. val totalNormalTabs = (normalTabs + remainderTabs) val selectedTabIndex = totalNormalTabs.findSelectedIndex(selectedTabId) - - // N.B: For regular tabs, we cannot use submitList alone, because the `TabsAdapter` needs to have a reference - // to the new tabs in it. We considered moving the call within `updateTabs` but this would have the side-effect - // of notifying the adapter twice for private tabs which shared the `TabsAdapter`. concatAdapter.browserAdapter.updateTabs(Tabs(totalNormalTabs, selectedTabIndex)) - concatAdapter.browserAdapter.submitList(totalNormalTabs) } override fun isTabSelected(tabs: Tabs, position: Int): Boolean = false - override fun onTabsChanged(position: Int, count: Int) = Unit - override fun onTabsInserted(position: Int, count: Int) = Unit - override fun onTabsMoved(fromPosition: Int, toPosition: Int) = Unit - override fun onTabsRemoved(position: Int, count: Int) = Unit } private fun List.findSelectedIndex(tabId: String?): Int { diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsAdapter.kt index 77aa6509c..6533009f7 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsAdapter.kt @@ -37,6 +37,8 @@ abstract class TabsAdapter( override fun updateTabs(tabs: Tabs) { this.tabs = tabs + submitList(tabs.list) + notifyObservers { onTabsUpdated() } } @@ -47,23 +49,9 @@ abstract class TabsAdapter( holder.bind(tabs.list[position], isTabSelected(tabs, position), styling, this) } - override fun getItemCount(): Int = tabs?.list?.size ?: 0 - final override fun isTabSelected(tabs: Tabs, position: Int): Boolean = tabs.selectedIndex == position - final override fun onTabsChanged(position: Int, count: Int) = - notifyItemRangeChanged(position, count) - - final override fun onTabsInserted(position: Int, count: Int) = - notifyItemRangeInserted(position, count) - - final override fun onTabsMoved(fromPosition: Int, toPosition: Int) = - notifyItemMoved(fromPosition, toPosition) - - final override fun onTabsRemoved(position: Int, count: Int) = - notifyItemRangeRemoved(position, count) - private object DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Tab, newItem: Tab): Boolean { return oldItem.id == newItem.id diff --git a/app/src/test/java/org/mozilla/fenix/tabstray/viewholders/AbstractBrowserPageViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/tabstray/viewholders/AbstractBrowserPageViewHolderTest.kt index 7bbff9acc..fc39a0ebd 100644 --- a/app/src/test/java/org/mozilla/fenix/tabstray/viewholders/AbstractBrowserPageViewHolderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabstray/viewholders/AbstractBrowserPageViewHolderTest.kt @@ -51,7 +51,6 @@ class AbstractBrowserPageViewHolderTest { selectedIndex = 0 ) ) - adapter.onTabsInserted(0, 1) assertTrue(trayList.visibility == VISIBLE) assertTrue(emptyList.visibility == GONE) @@ -74,7 +73,6 @@ class AbstractBrowserPageViewHolderTest { selectedIndex = 0 ) ) - adapter.onTabsInserted(0, 0) assertTrue(trayList.visibility == GONE) assertTrue(emptyList.visibility == VISIBLE) From a75d46dfe19d799da7691385ee8e54b77d2be110 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Thu, 7 Oct 2021 23:17:25 -0400 Subject: [PATCH 023/563] Update Android Components to 95.0.20211008015247 --- buildSrc/src/main/java/AndroidComponents.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 37984dcbd..41aa7670a 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "95.0.20211006190137" + const val VERSION = "95.0.20211008015247" } From 6edd98915234abcdb51bd5e183bce5473b7b1049 Mon Sep 17 00:00:00 2001 From: "codrut.topliceanu" Date: Thu, 7 Oct 2021 10:48:42 +0300 Subject: [PATCH 024/563] For #20992 - Speculative fix for TopSitesPagerAdapter crash --- .../org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt index 0d35277da..1a1c08c82 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt @@ -59,7 +59,10 @@ class TopSitesPagerAdapter( // Update new list with the changed items currentPageChangedItems.forEach { item -> - refreshedItems[item.first - (position * TOP_SITES_PER_PAGE)] = item.second + val index = item.first - (position * TOP_SITES_PER_PAGE) + if (index in refreshedItems.indices) { + refreshedItems[index] = item.second + } } // Display the updated list without any of the removed items From 681fc216ac0a1bfe8c78ee0ca8d99b6742e52f9d Mon Sep 17 00:00:00 2001 From: AndiAJ Date: Tue, 5 Oct 2021 12:00:14 +0300 Subject: [PATCH 025/563] Fix for ambiguous tab_item --- .../org/mozilla/fenix/ui/robots/TabDrawerRobot.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 8dd4431af..5f58dfb9b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -419,9 +419,17 @@ private fun assertExistingOpenTabs(title: String) { } } -private fun assertExistingTabList() = - onView(allOf(withId(R.id.tab_item))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) +private fun assertExistingTabList() { + mDevice.findObject( + UiSelector().resourceId("$packageName:id/tabsTray") + ).waitForExists(waitingTime) + + assertTrue( + mDevice.findObject( + UiSelector().resourceId("$packageName:id/tab_item") + ).waitForExists(waitingTime) + ) +} private fun assertNoTabsOpenedText() = onView(withId(R.id.tab_tray_empty_view)) From 8d7e5dd4b70215582f944075504548a5433f6f7b Mon Sep 17 00:00:00 2001 From: AndiAJ Date: Tue, 5 Oct 2021 13:06:13 +0300 Subject: [PATCH 026/563] Fix for ambiguous tabstray_close --- .../java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 5f58dfb9b..6302f1c43 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -376,7 +376,8 @@ fun tabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition { private fun tabMediaControlButton() = onView(withId(R.id.play_pause_button)) -private fun closeTabButton() = onView(withId(R.id.mozac_browser_tabstray_close)) +private fun closeTabButton() = + mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_tabstray_close")) private fun assertCloseTabsButton(title: String) = onView( allOf( From 66ac309d40d9002db5255653b994d89abb9b4983 Mon Sep 17 00:00:00 2001 From: AndiAJ Date: Tue, 5 Oct 2021 13:52:38 +0300 Subject: [PATCH 027/563] Fix for ambiguous tabstray_title and with text --- .../mozilla/fenix/ui/robots/TabDrawerRobot.kt | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 6302f1c43..2271ce502 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -8,11 +8,9 @@ package org.mozilla.fenix.ui.robots import android.content.Context import android.view.View -import androidx.recyclerview.widget.RecyclerView import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.NoMatchingViewException import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction import androidx.test.espresso.action.GeneralLocation @@ -21,9 +19,7 @@ import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.longClick import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers -import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId @@ -407,16 +403,23 @@ private fun assertExistingOpenTabs(title: String) { ) .waitForExists(waitingTime) - tab(title).check(matches(isDisplayed())) - } catch (e: NoMatchingViewException) { - onView(withId(R.id.tabsTray)).perform( - RecyclerViewActions.scrollTo( - allOf( - withId(R.id.mozac_browser_tabstray_title), - withText(title) - ) - ) - ).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + assertTrue( + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/mozac_browser_tabstray_title") + .textContains(title) + ).waitForExists(waitingTime) + ) + } catch (e: AssertionError) { + println("The tab wasn't found") + mDevice.findObject(UiSelector().resourceId("$packageName:id/tabsTray")).swipeUp(2) + assertTrue( + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/mozac_browser_tabstray_title") + .textContains(title) + ).waitForExists(waitingTime) + ) } } From c9ca6f01b58a1969fae118b5dbd183725f7a2ccf Mon Sep 17 00:00:00 2001 From: AndiAJ Date: Fri, 8 Oct 2021 11:42:34 +0300 Subject: [PATCH 028/563] Fix for ambiguous mozac_browser_tabstray_close and with content description --- .../org/mozilla/fenix/ui/robots/TabDrawerRobot.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 2271ce502..1ad0e9893 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -375,13 +375,13 @@ private fun tabMediaControlButton() = onView(withId(R.id.play_pause_button)) private fun closeTabButton() = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_tabstray_close")) private fun assertCloseTabsButton(title: String) = - onView( - allOf( - withId(R.id.mozac_browser_tabstray_close), - withContentDescription("Close tab $title") - ) + assertTrue( + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/mozac_browser_tabstray_close") + .descriptionContains("Close tab $title") + ).waitForExists(waitingTime) ) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) private fun normalBrowsingButton() = onView( anyOf( From 19c4186f0a1809ba421361252fc05fb2b9ae0ca3 Mon Sep 17 00:00:00 2001 From: AndiAJ Date: Fri, 8 Oct 2021 11:46:20 +0300 Subject: [PATCH 029/563] Remove closeTabViaXButton() and replace it with closeTab() in the UI tests --- .../org/mozilla/fenix/ui/TabbedBrowsingTest.kt | 4 ++-- .../org/mozilla/fenix/ui/robots/TabDrawerRobot.kt | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index abe2f4ce9..b165bf80a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -144,7 +144,7 @@ class TabbedBrowsingTest { }.openNewTabAndEnterToBrowser(genericURL.url) { }.openTabDrawer { verifyExistingOpenTabs("Test_Page_1") - closeTabViaXButton("Test_Page_1") + closeTab() verifySnackBarText("Tab closed") snackBarButtonClick("UNDO") } @@ -187,7 +187,7 @@ class TabbedBrowsingTest { }.openTabDrawer { verifyExistingOpenTabs("Test_Page_1") verifyCloseTabsButton("Test_Page_1") - closeTabViaXButton("Test_Page_1") + closeTab() verifySnackBarText("Private tab closed") snackBarButtonClick("UNDO") } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 1ad0e9893..f03b725ec 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -114,21 +114,6 @@ class TabDrawerRobot { } } - fun closeTabViaXButton(title: String) { - mDevice.findObject(UiSelector().text(title)).waitForExists(waitingTime) - var retries = 0 // number of retries before failing, will stop at 2 - do { - val closeButton = onView( - allOf( - withId(R.id.mozac_browser_tabstray_close), - withContentDescription("Close tab $title") - ) - ) - closeButton.perform(click()) - retries++ - } while (mDevice.findObject(UiSelector().text(title)).exists() && retries < 3) - } - fun verifySnackBarText(expectedText: String) { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mDevice.waitNotNull(findObject(By.text(expectedText)), TestAssetHelper.waitingTime) From 2eae152beb6551af8e691844b677102949b87600 Mon Sep 17 00:00:00 2001 From: AndiAJ Date: Fri, 8 Oct 2021 11:59:50 +0300 Subject: [PATCH 030/563] Remove openNewTabAndEnterToBrowser() and replace it with enterURLAndEnterToBrowser() in the UI tests --- .../mozilla/fenix/ui/SettingsAddonsTest.kt | 13 ++++++------- .../mozilla/fenix/ui/TabbedBrowsingTest.kt | 10 ++++++---- .../fenix/ui/robots/NavigationToolbarRobot.kt | 19 ------------------- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt index ea683c369..0ca4b3757 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt @@ -1,22 +1,21 @@ package org.mozilla.fenix.ui -import android.view.View -import androidx.test.espresso.IdlingRegistry -import org.mozilla.fenix.helpers.TestAssetHelper - /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import android.view.View +import androidx.test.espresso.IdlingRegistry import okhttp3.mockwebserver.MockWebServer -import org.junit.Rule -import org.junit.Before import org.junit.After +import org.junit.Before +import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource +import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar @@ -80,7 +79,7 @@ class SettingsAddonsTest { val addonName = "uBlock Origin" navigationToolbar {} - .openNewTabAndEnterToBrowser(defaultWebPage.url) {} + .enterURLAndEnterToBrowser(defaultWebPage.url) {} .openThreeDotMenu {} .openAddonsManagerMenu { addonsListIdlingResource = diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index b165bf80a..a80147ad3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -65,7 +65,7 @@ class TabbedBrowsingTest { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { - }.openNewTabAndEnterToBrowser(defaultWebPage.url) { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { mDevice.waitForIdle() verifyTabCounter("1") }.openTabDrawer { @@ -91,7 +91,7 @@ class TabbedBrowsingTest { homeScreen {}.togglePrivateBrowsingMode() navigationToolbar { - }.openNewTabAndEnterToBrowser(defaultWebPage.url) { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { mDevice.waitForIdle() verifyTabCounter("1") }.openTabDrawer { @@ -141,7 +141,8 @@ class TabbedBrowsingTest { val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { - }.openNewTabAndEnterToBrowser(genericURL.url) { + }.enterURLAndEnterToBrowser(genericURL.url) { + mDevice.waitForIdle() }.openTabDrawer { verifyExistingOpenTabs("Test_Page_1") closeTab() @@ -183,7 +184,8 @@ class TabbedBrowsingTest { homeScreen { }.togglePrivateBrowsingMode() navigationToolbar { - }.openNewTabAndEnterToBrowser(genericURL.url) { + }.enterURLAndEnterToBrowser(genericURL.url) { + mDevice.waitForIdle() }.openTabDrawer { verifyExistingOpenTabs("Test_Page_1") verifyCloseTabsButton("Test_Page_1") diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt index bcda5524c..4cdfbd0ff 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt @@ -150,25 +150,6 @@ class NavigationToolbarRobot { return TabDrawerRobot.Transition() } - fun openNewTabAndEnterToBrowser( - url: Uri, - interact: BrowserRobot.() -> Unit - ): BrowserRobot.Transition { - sessionLoadedIdlingResource = SessionLoadedIdlingResource() - mDevice.waitNotNull(Until.findObject(By.res("$packageName:id/toolbar")), waitingTime) - urlBar().click() - awesomeBar().setText(url.toString()) - mDevice.pressEnter() - - runWithIdleRes(sessionLoadedIdlingResource) { - onView(ViewMatchers.withResourceName("browserLayout")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - } - - BrowserRobot().interact() - return BrowserRobot.Transition() - } - fun visitLinkFromClipboard(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { mDevice.waitNotNull( Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_clear_view")), From 1cbdb6e684c6270c3c5f7f6fbffbb7b86d38ff4c Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Fri, 8 Oct 2021 12:10:10 +0000 Subject: [PATCH 031/563] Update Android Components version to 95.0.20211008105820. --- app/src/main/java/org/mozilla/fenix/components/UseCases.kt | 3 ++- buildSrc/src/main/java/AndroidComponents.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt index 76441d6d3..63ca8f211 100644 --- a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt @@ -63,7 +63,8 @@ class UseCases( val searchUseCases by lazyMonitored { SearchUseCases( store, - tabsUseCases + tabsUseCases, + sessionUseCases ) } diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 41aa7670a..943e63ec8 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "95.0.20211008015247" + const val VERSION = "95.0.20211008105820" } From bcc40e8e468c196a196222db1989f585a2dc9729 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Fri, 8 Oct 2021 00:30:25 -0400 Subject: [PATCH 032/563] Issue #21794: Reverse chevron for inactive tabs --- app/src/main/res/layout/inactive_header_item.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/layout/inactive_header_item.xml b/app/src/main/res/layout/inactive_header_item.xml index f61c871ac..6ace4d6a6 100644 --- a/app/src/main/res/layout/inactive_header_item.xml +++ b/app/src/main/res/layout/inactive_header_item.xml @@ -47,7 +47,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" - android:rotation="180" android:contentDescription="@string/tab_menu" app:layout_constraintBottom_toBottomOf="@id/inactive_title" app:layout_constraintStart_toEndOf="@id/inactive_title" From d0bb77fc2b4fac244c4bfff352e3021fa4d60169 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Fri, 8 Oct 2021 12:03:26 -0400 Subject: [PATCH 033/563] For #21809 - Adjust the padding between the Pocket section --- .../viewholders/pocket/PocketStoriesViewHolder.kt | 2 +- app/src/main/res/layout/customize_home_list_item.xml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt index 358e269e7..3d09211e2 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/pocket/PocketStoriesViewHolder.kt @@ -97,7 +97,7 @@ fun PocketStories( } } - Column(modifier = Modifier.padding(vertical = 44.dp)) { + Column(modifier = Modifier.padding(top = 72.dp)) { SectionHeader( text = stringResource(R.string.pocket_stories_header_1), modifier = Modifier diff --git a/app/src/main/res/layout/customize_home_list_item.xml b/app/src/main/res/layout/customize_home_list_item.xml index 4a9dde779..b6c8658af 100644 --- a/app/src/main/res/layout/customize_home_list_item.xml +++ b/app/src/main/res/layout/customize_home_list_item.xml @@ -8,9 +8,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingVertical="16dp" android:layout_marginHorizontal="@dimen/home_item_horizontal_margin" - android:layout_marginTop="24dp" + android:layout_marginTop="68dp" android:background="?android:attr/selectableItemBackground">