From 5c0c4117b5129e13369d4b7918263b86268e22b9 Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Mon, 22 Mar 2021 15:35:04 +0000 Subject: [PATCH 001/315] Update Android Components version to 74.0.20210322143147. --- 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 e35725099..564238efa 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 = "74.0.20210321143134" + const val VERSION = "74.0.20210322143147" } From 54db8f3fde08532b05a7f62f0b648a23aa693d0b Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Mon, 22 Mar 2021 14:28:36 -0400 Subject: [PATCH 002/315] Revert "For #17805 - Fix adjustResize deprecation (#18252)" This reverts commit 38f906a6 --- app/src/main/AndroidManifest.xml | 7 +-- .../java/org/mozilla/fenix/HomeActivity.kt | 3 -- .../customtabs/ExternalAppBrowserActivity.kt | 9 ---- .../java/org/mozilla/fenix/ext/Activity.kt | 45 ------------------- .../fenix/search/SearchDialogFragment.kt | 11 ++--- .../settings/account/AuthCustomTabActivity.kt | 8 ---- app/src/main/res/values/styles.xml | 2 + 7 files changed, 10 insertions(+), 75 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e6e371cff..2b9d15bd9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -77,7 +77,8 @@ android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize|layoutDirection|smallestScreenSize|screenLayout" android:launchMode="singleTask" android:resizeableActivity="true" - android:supportsPictureInPicture="true"> + android:supportsPictureInPicture="true" + android:windowSoftInputMode="adjustResize"> @@ -134,7 +135,7 @@ android:taskAffinity="" android:resizeableActivity="true" android:supportsPictureInPicture="true" - android:windowSoftInputMode="stateAlwaysHidden" /> + android:windowSoftInputMode="adjustResize|stateAlwaysHidden" /> + android:windowSoftInputMode="adjustResize|stateAlwaysHidden" /> diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index 5a20d489a..c85a39d76 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -77,7 +77,6 @@ import org.mozilla.fenix.exceptions.trackingprotection.TrackingProtectionExcepti import org.mozilla.fenix.ext.alreadyOnDestination import org.mozilla.fenix.ext.breadcrumb import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.enableSystemInsetsHandling import org.mozilla.fenix.ext.measureNoInline import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.nav @@ -256,8 +255,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { components.core.requestInterceptor.setNavigationController(navHost.navController) - enableSystemInsetsHandling() - StartupTimeline.onActivityCreateEndHome(this) // DO NOT MOVE ANYTHING BELOW HERE. } diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt index 0ab6311a0..689a6aa4c 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivity.kt @@ -5,8 +5,6 @@ package org.mozilla.fenix.customtabs import android.content.Intent -import android.os.Bundle -import android.os.PersistableBundle import androidx.annotation.VisibleForTesting import androidx.navigation.NavDestination import androidx.navigation.NavDirections @@ -22,7 +20,6 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.NavGraphDirections import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.enableSystemInsetsHandling import java.security.InvalidParameterException /** @@ -31,12 +28,6 @@ import java.security.InvalidParameterException */ @Suppress("TooManyFunctions") open class ExternalAppBrowserActivity : HomeActivity() { - - override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { - super.onCreate(savedInstanceState, persistentState) - enableSystemInsetsHandling() - } - override fun onResume() { super.onResume() diff --git a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt index 3f70af653..e70b3fa51 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt @@ -5,12 +5,7 @@ package org.mozilla.fenix.ext import android.app.Activity -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES import android.view.View -import android.view.Window -import android.view.WindowInsets -import android.view.WindowInsets.Type import android.view.WindowManager import mozilla.components.concept.base.crash.Breadcrumb @@ -53,43 +48,3 @@ fun Activity.breadcrumb( ) ) } - -/** - * Handles inset changes for the whole activity. - * - * The deprecation of [WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE] in [VERSION_CODES.R] - * means inset changes have to be handled with a [View.OnApplyWindowInsetsListener]. - * [Window.setDecorFitsSystemWindows] false tells the system that the app will handle all insets. - * When a keyboard is opened [WindowInsets.getInsets] of [Type.ime] updates accordingly. - * - * See https://github.com/mozilla-mobile/fenix/issues/17805. - * */ -fun Activity.enableSystemInsetsHandling() { - if (VERSION.SDK_INT >= VERSION_CODES.R) { - val currentInsetTypes = mutableSetOf() - - currentInsetTypes.add(Type.systemBars()) - currentInsetTypes.add(Type.statusBars()) - currentInsetTypes.add(Type.mandatorySystemGestures()) - currentInsetTypes.add(Type.ime()) - - window.setDecorFitsSystemWindows(false) - - window.decorView.setOnApplyWindowInsetsListener { v, _ -> - val currentInsetTypeMask = currentInsetTypes.fold(0) { accumulator, type -> - accumulator or type - } - val insets = window.decorView.rootWindowInsets.getInsets(currentInsetTypeMask) - v.setPadding(insets.left, insets.top, insets.right, insets.bottom) - - WindowInsets.Builder() - .setInsets(currentInsetTypeMask, insets) - .build() - } - } else { - @Suppress("DEPRECATION") - window.setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE - ) - } -} 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 32ca97d5f..780724462 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt @@ -13,8 +13,7 @@ import android.content.Intent import android.graphics.Color import android.graphics.Typeface import android.graphics.drawable.ColorDrawable -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES +import android.os.Build import android.os.Bundle import android.speech.RecognizerIntent import android.text.style.StyleSpan @@ -90,8 +89,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { // https://github.com/mozilla-mobile/fenix/issues/14279 // To prevent GeckoView from resizing we're going to change the softInputMode to not adjust // the size of the window. - if (VERSION.SDK_INT < VERSION_CODES.R) - requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) + requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) // Refocus the toolbar editing and show keyboard if the QR fragment isn't showing if (childFragmentManager.findFragmentByTag(QR_FRAGMENT_TAG) == null) { toolbarView.view.edit.focus() @@ -104,8 +102,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { // Let's reset back to the default behavior after we're done searching // This will be addressed on https://github.com/mozilla-mobile/fenix/issues/17805 @Suppress("DEPRECATION") - if (VERSION.SDK_INT < VERSION_CODES.R) - requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) + requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) } override fun onCreate(savedInstanceState: Bundle?) { @@ -349,7 +346,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { private fun updateAccessibilityTraversalOrder() { val searchWrapperId = search_wrapper.id - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { qr_scan_button.accessibilityTraversalAfter = searchWrapperId search_engines_shortcut_button.accessibilityTraversalAfter = searchWrapperId fill_link_from_clipboard.accessibilityTraversalAfter = searchWrapperId diff --git a/app/src/main/java/org/mozilla/fenix/settings/account/AuthCustomTabActivity.kt b/app/src/main/java/org/mozilla/fenix/settings/account/AuthCustomTabActivity.kt index 2f6279001..98b986dc7 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/account/AuthCustomTabActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/account/AuthCustomTabActivity.kt @@ -4,25 +4,17 @@ package org.mozilla.fenix.settings.account -import android.os.Bundle -import android.os.PersistableBundle import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.OAuthAccount import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.enableSystemInsetsHandling /** * A special custom tab for signing into a Firefox Account. The activity is closed once the user is signed in. */ class AuthCustomTabActivity : ExternalAppBrowserActivity() { - override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { - super.onCreate(savedInstanceState, persistentState) - enableSystemInsetsHandling() - } - private val accountStateObserver = object : AccountObserver { /** * Navigate away from this activity when we have successful authentication diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 90352f810..c0d2b4ad2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -342,6 +342,7 @@ @style/Animation.Design.BottomSheetDialog true false + adjustResize false false @null @@ -618,6 +619,7 @@ @android:color/transparent true false + adjustResize false false @null From d0a45bab21a177b57c14dbee8ec6a57bbd8435be Mon Sep 17 00:00:00 2001 From: mcarare Date: Wed, 17 Mar 2021 19:35:51 +0200 Subject: [PATCH 003/315] For #17799: Add extensions submenu item. --- .../mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt | 3 +-- .../fenix/components/toolbar/DefaultToolbarMenu.kt | 10 +++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt index 71d03cbc5..64146d02f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt @@ -411,8 +411,7 @@ private fun assertSettingsButton() = settingsButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(isCompletelyDisplayed())) -private val addOnsText = if (FeatureFlags.toolbarMenuFeature) "Extensions" else "Add-ons" -private fun addOnsButton() = onView(allOf(withText(addOnsText))) +private fun addOnsButton() = onView(allOf(withText("Add-ons"))) private fun assertAddOnsButton() { onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) addOnsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt index 38ac495d2..5bc0f4ca3 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt @@ -399,13 +399,9 @@ class DefaultToolbarMenu( onItemTapped.invoke(ToolbarMenu.Item.Downloads) } - val extensionsItem = BrowserMenuImageText( - context.getString(R.string.browser_menu_extensions), - R.drawable.ic_addons_extensions, - primaryTextColor() - ) { - onItemTapped.invoke(ToolbarMenu.Item.AddonsManager) - } + val extensionsItem = WebExtensionPlaceholderMenuItem( + id = WebExtensionPlaceholderMenuItem.MAIN_EXTENSIONS_MENU_ID + ) val syncedTabs = BrowserMenuImageText( label = context.getString(R.string.synced_tabs), From 43c54b7006d0d28f852bf1b93b75dcbbba004b7d Mon Sep 17 00:00:00 2001 From: "Vitaly V. Pinchuk" Date: Tue, 23 Mar 2021 12:46:10 +0300 Subject: [PATCH 004/315] For #18395: Dismiss contextual menu when entering/exiting Reader Mode --- .../java/org/mozilla/fenix/HomeActivity.kt | 18 ++++++++++++++++++ .../fenix/browser/BaseBrowserFragment.kt | 3 ++- .../browser/readermode/ReaderModeController.kt | 5 ++++- .../DefaultReaderModeControllerTest.kt | 16 ++++++++++++++-- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index c85a39d76..5052bb89d 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -16,6 +16,7 @@ import android.util.AttributeSet import android.view.KeyEvent import android.view.LayoutInflater import android.view.View +import android.view.ActionMode import android.view.ViewConfiguration import android.view.WindowManager.LayoutParams.FLAG_SECURE import androidx.annotation.CallSuper @@ -165,6 +166,9 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { private lateinit var navigationToolbar: Toolbar + // Tracker for contextual menu (Copy|Search|Select all|etc...) + private var actionMode: ActionMode? = null + final override fun onCreate(savedInstanceState: Bundle?): Unit = PerfStartup.homeActivityOnCreate.measureNoInline { // DO NOT MOVE ANYTHING ABOVE THIS addMarker CALL. components.core.engine.profiler?.addMarker("Activity.onCreate", "HomeActivity") @@ -519,6 +523,20 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { else -> super.onCreateView(parent, name, context, attrs) } + override fun onActionModeStarted(mode: ActionMode?) { + actionMode = mode + super.onActionModeStarted(mode) + } + + override fun onActionModeFinished(mode: ActionMode?) { + actionMode = null + super.onActionModeFinished(mode) + } + + fun finishActionMode() { + actionMode?.finish().also { actionMode = null } + } + @Suppress("MagicNumber") // Defining the positions as constants doesn't seem super useful here. private fun actionSorter(actions: Array): Array { 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 9b8d06127..58ff3b3cd 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -282,7 +282,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit val readerMenuController = DefaultReaderModeController( readerViewFeature, view.readerViewControlsBar, - isPrivate = activity.browsingModeManager.mode.isPrivate + isPrivate = activity.browsingModeManager.mode.isPrivate, + onReaderModeChanged = { activity.finishActionMode() } ) val browserToolbarController = DefaultBrowserToolbarController( store = store, diff --git a/app/src/main/java/org/mozilla/fenix/browser/readermode/ReaderModeController.kt b/app/src/main/java/org/mozilla/fenix/browser/readermode/ReaderModeController.kt index 478f5dc89..bc24e7dfb 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/readermode/ReaderModeController.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/readermode/ReaderModeController.kt @@ -24,9 +24,11 @@ interface ReaderModeController { class DefaultReaderModeController( private val readerViewFeature: ViewBoundFeatureWrapper, private val readerViewControlsBar: View, - private val isPrivate: Boolean = false + private val isPrivate: Boolean = false, + private val onReaderModeChanged: () -> Unit = {} ) : ReaderModeController { override fun hideReaderView() { + onReaderModeChanged() readerViewFeature.withFeature { it.hideReaderView() it.hideControls() @@ -34,6 +36,7 @@ class DefaultReaderModeController( } override fun showReaderView() { + onReaderModeChanged() readerViewFeature.withFeature { it.showReaderView() } } diff --git a/app/src/test/java/org/mozilla/fenix/browser/readermode/DefaultReaderModeControllerTest.kt b/app/src/test/java/org/mozilla/fenix/browser/readermode/DefaultReaderModeControllerTest.kt index bb8e3e3a5..d9cd83df5 100644 --- a/app/src/test/java/org/mozilla/fenix/browser/readermode/DefaultReaderModeControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/browser/readermode/DefaultReaderModeControllerTest.kt @@ -32,6 +32,7 @@ class DefaultReaderModeControllerTest { private lateinit var readerViewFeature: ReaderViewFeature private lateinit var featureWrapper: ViewBoundFeatureWrapper private lateinit var readerViewControlsBar: View + private lateinit var onReaderModeChanged: () -> Unit @Before fun setup() { @@ -50,6 +51,7 @@ class DefaultReaderModeControllerTest { view = mockk(relaxed = true) ) readerViewControlsBar = mockk(relaxed = true) + onReaderModeChanged = mockk(relaxed = true) every { readerViewFeature.hideReaderView() } returns Unit every { readerViewFeature.showReaderView() } returns Unit @@ -59,17 +61,27 @@ class DefaultReaderModeControllerTest { @Test fun testHideReaderView() { - val controller = DefaultReaderModeController(featureWrapper, readerViewControlsBar) + val controller = DefaultReaderModeController( + featureWrapper, + readerViewControlsBar, + onReaderModeChanged = onReaderModeChanged + ) controller.hideReaderView() verify { readerViewFeature.hideReaderView() } verify { readerViewFeature.hideControls() } + verify { onReaderModeChanged.invoke() } } @Test fun testShowReaderView() { - val controller = DefaultReaderModeController(featureWrapper, readerViewControlsBar) + val controller = DefaultReaderModeController( + featureWrapper, + readerViewControlsBar, + onReaderModeChanged = onReaderModeChanged + ) controller.showReaderView() verify { readerViewFeature.showReaderView() } + verify { onReaderModeChanged.invoke() } } @Test From cc2ba4ba97cd4fe7d72259dd0bd26f6ce7533a08 Mon Sep 17 00:00:00 2001 From: Mugurell Date: Tue, 23 Mar 2021 15:54:24 +0200 Subject: [PATCH 005/315] For #18585 - Don't use hardcoded String values in Onboarding unit test (#18597) Test if the welcome message has the expected structure and uses the expected String values, not what the string values are. --- .../onboarding/OnboardingHeaderViewHolderTest.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingHeaderViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingHeaderViewHolderTest.kt index f29821142..0600b4878 100644 --- a/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingHeaderViewHolderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingHeaderViewHolderTest.kt @@ -12,6 +12,7 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mozilla.fenix.R import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) @@ -27,8 +28,11 @@ class OnboardingHeaderViewHolderTest { @Test fun `bind header text`() { + val appName = testContext.getString(R.string.app_name) + val welcomeMessage = testContext.getString(R.string.onboarding_header, appName) + OnboardingHeaderViewHolder(view) - assertEquals("Welcome to Firefox Preview!", view.header_text.text) + assertEquals(welcomeMessage, view.header_text.text) } } From a8c53c6bf1bfd5fb5aaa0c3961f11643a3266406 Mon Sep 17 00:00:00 2001 From: Roger Yang Date: Tue, 23 Mar 2021 10:31:53 -0400 Subject: [PATCH 006/315] Closes #17791: Use updated URL with custom tabs when copying to clipboard (#18590) --- .../components/toolbar/BrowserToolbarView.kt | 2 +- .../mozilla/fenix/utils/ToolbarPopupWindow.kt | 15 ++++--- .../fenix/utils/ToolbarPopupWindowTest.kt | 45 +++++++++++++++---- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt index b3b97311d..b64100299 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt @@ -87,7 +87,7 @@ class BrowserToolbarView( view.display.setOnUrlLongClickListener { ToolbarPopupWindow.show( WeakReference(view), - customTabSession, + customTabSession?.id, interactor::onBrowserToolbarPasteAndGo, interactor::onBrowserToolbarPaste ) diff --git a/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt b/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt index f9b349fce..db2d0b5a9 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt @@ -16,18 +16,18 @@ import androidx.core.view.isVisible import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.browser_toolbar_popup_window.view.* import mozilla.components.browser.state.selector.selectedTab -import mozilla.components.browser.state.state.CustomTabSessionState import mozilla.components.browser.state.store.BrowserStore import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import java.lang.ref.WeakReference +import mozilla.components.browser.state.selector.findCustomTab object ToolbarPopupWindow { fun show( view: WeakReference, - customTabSession: CustomTabSessionState? = null, + customTabId: String? = null, handlePasteAndGo: (String) -> Unit, handlePaste: (String) -> Unit, copyVisible: Boolean = true @@ -36,7 +36,7 @@ object ToolbarPopupWindow { val clipboard = context.components.clipboardHandler if (!copyVisible && clipboard.text.isNullOrEmpty()) return - val isCustomTabSession = customTabSession != null + val isCustomTabSession = customTabId != null val customView = LayoutInflater.from(context) .inflate(R.layout.browser_toolbar_popup_window, null) @@ -63,7 +63,7 @@ object ToolbarPopupWindow { popupWindow.dismiss() clipboard.text = getUrlForClipboard( it.context.components.core.store, - customTabSession + customTabId ) view.get()?.let { @@ -101,10 +101,11 @@ object ToolbarPopupWindow { @VisibleForTesting internal fun getUrlForClipboard( store: BrowserStore, - customTabSession: CustomTabSessionState? = null + customTabId: String? = null ): String? { - return if (customTabSession != null) { - customTabSession.content.url + return if (customTabId != null) { + val customTab = store.state.findCustomTab(customTabId) + customTab?.content?.url } else { val selectedTab = store.state.selectedTab selectedTab?.readerState?.activeUrl ?: selectedTab?.content?.url diff --git a/app/src/test/java/org/mozilla/fenix/utils/ToolbarPopupWindowTest.kt b/app/src/test/java/org/mozilla/fenix/utils/ToolbarPopupWindowTest.kt index 69ef82b3a..d56f1b50b 100644 --- a/app/src/test/java/org/mozilla/fenix/utils/ToolbarPopupWindowTest.kt +++ b/app/src/test/java/org/mozilla/fenix/utils/ToolbarPopupWindowTest.kt @@ -4,35 +4,44 @@ package org.mozilla.fenix.utils -import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineDispatcher +import mozilla.components.browser.state.action.ContentAction import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.ReaderState import mozilla.components.browser.state.state.createCustomTab import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.support.test.ext.joinBlocking +import mozilla.components.support.test.rule.MainCoroutineRule import org.junit.Assert.assertEquals +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +@ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class ToolbarPopupWindowTest { + private val testDispatcher = TestCoroutineDispatcher() - @Test - fun getUrlForClipboard() { - val customTabSession = createCustomTab("https://mozilla.org") + @get:Rule + val coroutinesTestRule = MainCoroutineRule(testDispatcher) + @Test + fun `getUrlForClipboard should get the right URL`() { // Custom tab + val customTabSession = createCustomTab("https://mozilla.org") + var store = BrowserStore(BrowserState(customTabs = listOf(customTabSession))) assertEquals( "https://mozilla.org", - ToolbarPopupWindow.getUrlForClipboard(mockk(), customTabSession) + ToolbarPopupWindow.getUrlForClipboard(store, customTabSession.id) ) // Regular tab val regularTab = createTab(url = "http://firefox.com") - var store = - BrowserStore(BrowserState(tabs = listOf(regularTab), selectedTabId = regularTab.id)) - assertEquals(regularTab.content.url, ToolbarPopupWindow.getUrlForClipboard(store)) + store = BrowserStore(BrowserState(tabs = listOf(regularTab), selectedTabId = regularTab.id)) + assertEquals("http://firefox.com", ToolbarPopupWindow.getUrlForClipboard(store)) // Reader Tab val readerTab = createTab( @@ -40,6 +49,24 @@ class ToolbarPopupWindowTest { readerState = ReaderState(active = true, activeUrl = "https://blog.mozilla.org/123") ) store = BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id)) - assertEquals(readerTab.readerState.activeUrl, ToolbarPopupWindow.getUrlForClipboard(store)) + assertEquals("https://blog.mozilla.org/123", ToolbarPopupWindow.getUrlForClipboard(store)) + } + + @Test + fun `getUrlForClipboard should get the updated URL`() { + // Custom tab + val customTabSession = createCustomTab("https://mozilla.org") + var store = BrowserStore(BrowserState(customTabs = listOf(customTabSession))) + store.dispatch(ContentAction.UpdateUrlAction(customTabSession.id, "https://firefox.com")).joinBlocking() + assertEquals( + "https://firefox.com", + ToolbarPopupWindow.getUrlForClipboard(store, customTabSession.id) + ) + + // Regular tab + val regularTab = createTab(url = "http://firefox.com") + store = BrowserStore(BrowserState(tabs = listOf(regularTab), selectedTabId = regularTab.id)) + store.dispatch(ContentAction.UpdateUrlAction(regularTab.id, "https://mozilla.org")).joinBlocking() + assertEquals("https://mozilla.org", ToolbarPopupWindow.getUrlForClipboard(store)) } } From 83018c813bf4a3bc4af1f0e405e313e7ef606e34 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 23 Mar 2021 11:08:18 -0400 Subject: [PATCH 007/315] Update version.txt to 89.0.0-beta.1 (#18602) --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 4e3c841a8..645c46766 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -88.0.0-beta.1 +89.0.0-beta.1 From 578d6b5205563c19bcc16cc911e260c24d4ff00f Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Tue, 23 Mar 2021 11:59:32 -0400 Subject: [PATCH 008/315] For #18240 - Add a Credit Card preference screen (#18410) - Removes an unused preference key "pref_key_credit_cards_addresses" --- .../fenix/settings/SettingsFragment.kt | 21 +++++++--- .../creditcards/CreditCardsSettingFragment.kt | 27 +++++++++++++ ...reference_credit_cards_add_credit_card.xml | 40 +++++++++++++++++++ app/src/main/res/navigation/nav_graph.xml | 17 ++++++++ app/src/main/res/values/dimens.xml | 9 +++++ app/src/main/res/values/preference_keys.xml | 11 ++++- app/src/main/res/values/strings.xml | 12 ++++++ .../main/res/xml/credit_cards_preferences.xml | 20 ++++++++++ app/src/main/res/xml/preferences.xml | 5 +++ .../res/xml/preferences_without_icons.xml | 21 ++++++---- 10 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt create mode 100644 app/src/main/res/layout/preference_credit_cards_add_credit_card.xml create mode 100644 app/src/main/res/xml/credit_cards_preferences.xml 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 161e45295..ce2c8ebb0 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -276,6 +276,9 @@ class SettingsFragment : PreferenceFragmentCompat() { resources.getString(R.string.pref_key_passwords) -> { SettingsFragmentDirections.actionSettingsFragmentToSavedLoginsAuthFragment() } + resources.getString(R.string.pref_key_credit_cards) -> { + SettingsFragmentDirections.actionSettingsFragmentToCreditCardsSettingFragment() + } resources.getString(R.string.pref_key_about) -> { SettingsFragmentDirections.actionSettingsFragmentToAboutFragment() } @@ -423,12 +426,18 @@ class SettingsFragment : PreferenceFragmentCompat() { } preferenceFxAOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater preferenceSyncOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater - findPreference( - getPreferenceKey(R.string.pref_key_debug_settings) - )?.isVisible = requireContext().settings().showSecretDebugMenuThisSession - findPreference( - getPreferenceKey(R.string.pref_key_secret_debug_info) - )?.isVisible = requireContext().settings().showSecretDebugMenuThisSession + + with(requireContext().settings()) { + findPreference( + getPreferenceKey(R.string.pref_key_credit_cards) + )?.isVisible = creditCardsFeature + findPreference( + getPreferenceKey(R.string.pref_key_debug_settings) + )?.isVisible = showSecretDebugMenuThisSession + findPreference( + getPreferenceKey(R.string.pref_key_secret_debug_info) + )?.isVisible = showSecretDebugMenuThisSession + } setupAmoCollectionOverridePreference(requireContext().settings()) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt new file mode 100644 index 000000000..57c956e99 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt @@ -0,0 +1,27 @@ +/* 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.creditcards + +import android.os.Bundle +import androidx.preference.PreferenceFragmentCompat +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.showToolbar + +/** + * "Credit cards" settings fragment displays a list of settings related to autofilling, adding and + * syncing credit cards. + */ +class CreditCardsSettingFragment : PreferenceFragmentCompat() { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.credit_cards_preferences, rootKey) + } + + override fun onResume() { + super.onResume() + + showToolbar(getString(R.string.preferences_credit_cards)) + } +} diff --git a/app/src/main/res/layout/preference_credit_cards_add_credit_card.xml b/app/src/main/res/layout/preference_credit_cards_add_credit_card.xml new file mode 100644 index 000000000..41c8b247c --- /dev/null +++ b/app/src/main/res/layout/preference_credit_cards_add_credit_card.xml @@ -0,0 +1,40 @@ + + + + + + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 23f548ae9..685929e00 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -443,6 +443,13 @@ app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 40e04af06..343a1a0c5 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -213,6 +213,15 @@ 12dp 8dp + + + 48dp + + 16dp + 16sp + 48dp diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index b876ba6c1..68b3fcfe2 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -7,7 +7,6 @@ pref_key_search_engine pref_key_add_Search_engine pref_key_passwords - pref_key_credit_cards_addresses pref_key_site_permissions pref_key_add_private_browsing_shortcut pref_key_accessibility @@ -169,6 +168,16 @@ pref_key_logins_secure_warning_sync pref_key_logins_secure_warning + + + pref_key_credit_cards + + pref_key_credit_cards_save_and_autofill_cards + + pref_key_credit_cards_sync_cards_across_devices + + pref_key_credit_cards_add_credit_card + pref_key_open_links_in_a_private_tab pref_key_open_links_in_external_app diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 195b78d79..b7c9a2cae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1512,6 +1512,18 @@ Sort logins menu + + + Credit cards + + Save and autofill cards + + Data is encrypted + + Sync cards across devices + + Add credit card + Add search engine diff --git a/app/src/main/res/xml/credit_cards_preferences.xml b/app/src/main/res/xml/credit_cards_preferences.xml new file mode 100644 index 000000000..21e9cb551 --- /dev/null +++ b/app/src/main/res/xml/credit_cards_preferences.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 16ae3f11e..bf3e03797 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -68,6 +68,11 @@ android:key="@string/pref_key_passwords" android:title="@string/preferences_passwords_logins_and_passwords" /> + + + app:allowDividerBelow="false" /> + android:layout="@layout/preference_category_no_icon_style"> + android:key="@string/pref_key_account_auth_error" /> + app:isPreferenceVisible="false" /> + app:isPreferenceVisible="false" /> + + + android:title="@string/preferences_private_browsing_options" /> + android:title="@string/preferences_customize_amo_collection" /> + android:title="@string/preferences_external_download_manager" /> Date: Tue, 23 Mar 2021 13:16:30 -0500 Subject: [PATCH 009/315] For #17190: notifications are updated when locale is changed (#18179) * Add intent processor for locale changes * Recreate notification and notify in the service * Use locale use cases to update notification * Use notification id instead of tag * Add locale use cases and restore locale in application * Send locale to service instead of string * Controller tests for locale * Update Android Components version to 74.0.20210323143308 Co-authored-by: Arturo Mejia --- .../org/mozilla/fenix/FenixApplication.kt | 5 +++ .../org/mozilla/fenix/components/UseCases.kt | 6 ++++ .../session/PrivateNotificationService.kt | 26 ++++++++++++-- .../DefaultLocaleSettingsController.kt | 8 +++-- .../advanced/LocaleSettingsFragment.kt | 14 +++++--- .../advanced/LocaleSettingsControllerTest.kt | 34 +++++++++++++------ buildSrc/src/main/java/AndroidComponents.kt | 2 +- 7 files changed, 74 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index e996309c1..3b0c50f1a 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -165,6 +165,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { initializeWebExtensionSupport() restoreBrowserState() restoreDownloads() + restoreLocale() // Just to make sure it is impossible for any application-services pieces // to invoke parts of itself that require complete megazord initialization @@ -213,6 +214,10 @@ open class FenixApplication : LocaleAwareApplication(), Provider { components.useCases.downloadUseCases.restoreDownloads() } + private fun restoreLocale() { + components.useCases.localeUseCases.restore() + } + private fun initVisualCompletenessQueueAndQueueTasks() { val queue = components.performance.visualCompletenessQueue.queue 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 956cda377..9249c8ab8 100644 --- a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt @@ -22,6 +22,7 @@ import mozilla.components.feature.tabs.CustomTabsUseCases import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.feature.top.sites.TopSitesStorage import mozilla.components.feature.top.sites.TopSitesUseCases +import mozilla.components.support.locale.LocaleUseCases import org.mozilla.fenix.perf.lazyMonitored import org.mozilla.fenix.utils.Mockable @@ -88,4 +89,9 @@ class UseCases( * Use cases that provide top sites management. */ val topSitesUseCase by lazyMonitored { TopSitesUseCases(topSitesStorage) } + + /** + * Use cases that handle locale management. + */ + val localeUseCases by lazyMonitored { LocaleUseCases(store) } } diff --git a/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt b/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt index 94f21a60a..2e0b47b03 100644 --- a/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt +++ b/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt @@ -16,6 +16,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.metrics +import java.util.Locale /** * Manages notifications for private tabs. @@ -33,9 +34,28 @@ class PrivateNotificationService : AbstractPrivateNotificationService() { override fun NotificationCompat.Builder.buildNotification() { setSmallIcon(R.drawable.ic_private_browsing) - setContentTitle(applicationContext.getString(R.string.app_name_private_4, getString(R.string.app_name))) - setContentText(applicationContext.getString(R.string.notification_pbm_delete_text_2)) - color = ContextCompat.getColor(this@PrivateNotificationService, R.color.pbm_notification_color) + setContentTitle( + applicationContext.getString( + R.string.app_name_private_4, + getString(R.string.app_name) + ) + ) + setContentText( + applicationContext.getString( + R.string.notification_pbm_delete_text_2 + ) + ) + color = ContextCompat.getColor( + this@PrivateNotificationService, + R.color.pbm_notification_color + ) + } + + /** + * Update the existing notification when the [Locale] has been changed. + */ + override fun notifyLocaleChanged() { + super.refreshNotification() } @SuppressLint("MissingSuperCall") diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt index 46f30d451..8b78c7592 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.settings.advanced import android.app.Activity import android.content.Context import mozilla.components.support.locale.LocaleManager +import mozilla.components.support.locale.LocaleUseCases import java.util.Locale interface LocaleSettingsController { @@ -17,7 +18,8 @@ interface LocaleSettingsController { class DefaultLocaleSettingsController( private val activity: Activity, - private val localeSettingsStore: LocaleSettingsStore + private val localeSettingsStore: LocaleSettingsStore, + private val localeUseCase: LocaleUseCases ) : LocaleSettingsController { override fun handleLocaleSelected(locale: Locale) { @@ -26,7 +28,7 @@ class DefaultLocaleSettingsController( return } localeSettingsStore.dispatch(LocaleSettingsAction.Select(locale)) - LocaleManager.setNewLocale(activity, locale.toLanguageTag()) + LocaleManager.setNewLocale(activity, localeUseCase, locale) LocaleManager.updateBaseConfiguration(activity, locale) activity.recreate() } @@ -36,7 +38,7 @@ class DefaultLocaleSettingsController( return } localeSettingsStore.dispatch(LocaleSettingsAction.Select(localeSettingsStore.state.localeList[0])) - LocaleManager.resetToSystemDefault(activity) + LocaleManager.resetToSystemDefault(activity, localeUseCase) LocaleManager.updateBaseConfiguration(activity, localeSettingsStore.state.localeList[0]) activity.recreate() } diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt index 4a307d29d..a2ee4533f 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt @@ -17,13 +17,15 @@ import kotlinx.android.synthetic.main.fragment_locale_settings.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.ktx.android.view.hideKeyboard +import mozilla.components.support.locale.LocaleUseCases import org.mozilla.fenix.R import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.showToolbar class LocaleSettingsFragment : Fragment() { - private lateinit var store: LocaleSettingsStore + private lateinit var localeSettingsStore: LocaleSettingsStore private lateinit var interactor: LocaleSettingsInteractor private lateinit var localeView: LocaleSettingsView @@ -39,7 +41,10 @@ class LocaleSettingsFragment : Fragment() { ): View? { val view = inflater.inflate(R.layout.fragment_locale_settings, container, false) - store = StoreProvider.get(this) { + val browserStore = requireContext().components.core.store + val localeUseCase = LocaleUseCases(browserStore) + + localeSettingsStore = StoreProvider.get(this) { LocaleSettingsStore( createInitialLocaleSettingsState(requireContext()) ) @@ -47,7 +52,8 @@ class LocaleSettingsFragment : Fragment() { interactor = LocaleSettingsInteractor( controller = DefaultLocaleSettingsController( activity = requireActivity(), - localeSettingsStore = store + localeSettingsStore = localeSettingsStore, + localeUseCase = localeUseCase ) ) localeView = LocaleSettingsView(view.locale_container, interactor) @@ -87,7 +93,7 @@ class LocaleSettingsFragment : Fragment() { @ExperimentalCoroutinesApi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - consumeFrom(store) { + consumeFrom(localeSettingsStore) { localeView.update(it) } } diff --git a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt index c1f4f463d..d55b6f2ea 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt @@ -15,6 +15,7 @@ import io.mockk.spyk import io.mockk.verify import io.mockk.verifyAll import mozilla.components.support.locale.LocaleManager +import mozilla.components.support.locale.LocaleUseCases import org.junit.Before import org.junit.Test import java.util.Locale @@ -23,13 +24,20 @@ class LocaleSettingsControllerTest { private val activity = mockk(relaxed = true) private val localeSettingsStore: LocaleSettingsStore = mockk(relaxed = true) + private val localeUseCases: LocaleUseCases = mockk(relaxed = true) private val mockState = LocaleSettingsState(mockk(), mockk(), mockk()) private lateinit var controller: DefaultLocaleSettingsController @Before fun setup() { - controller = spyk(DefaultLocaleSettingsController(activity, localeSettingsStore)) + controller = spyk( + DefaultLocaleSettingsController( + activity, + localeSettingsStore, + localeUseCases + ) + ) mockkObject(LocaleManager) mockkStatic("org.mozilla.fenix.settings.advanced.LocaleManagerExtensionKt") @@ -45,11 +53,13 @@ class LocaleSettingsControllerTest { verifyAll(inverse = true) { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) - LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) + LocaleManager.setNewLocale(activity, locale = selectedLocale) activity.recreate() } with(controller) { - verify(inverse = true) { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } + verify(inverse = true) { + LocaleManager.updateBaseConfiguration(activity, selectedLocale) + } } } @@ -57,8 +67,9 @@ class LocaleSettingsControllerTest { fun `set a new locale from the list if other locale is chosen`() { val selectedLocale = Locale("en", "UK") val otherLocale: Locale = mockk() + every { localeUseCases.notifyLocaleChanged } returns mockk() every { localeSettingsStore.state } returns mockState.copy(selectedLocale = otherLocale) - every { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } returns activity + every { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } returns activity with(controller) { every { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } just Runs } @@ -66,7 +77,7 @@ class LocaleSettingsControllerTest { controller.handleLocaleSelected(selectedLocale) verify { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) } - verify { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } + verify { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } verify { activity.recreate() } with(controller) { verify { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } @@ -76,9 +87,11 @@ class LocaleSettingsControllerTest { @Test fun `set a new locale from the list if default locale is not selected`() { val selectedLocale = Locale("en", "UK") + every { localeUseCases.notifyLocaleChanged } returns mockk() every { localeSettingsStore.state } returns mockState.copy(selectedLocale = selectedLocale) every { LocaleManager.getCurrentLocale(activity) } returns null - every { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } returns activity + every { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } returns activity + with(controller) { every { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } just Runs } @@ -86,7 +99,7 @@ class LocaleSettingsControllerTest { controller.handleLocaleSelected(selectedLocale) verify { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) } - verify { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } + verify { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } verify { activity.recreate() } with(controller) { verify { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } @@ -103,7 +116,7 @@ class LocaleSettingsControllerTest { verifyAll(inverse = true) { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) - LocaleManager.resetToSystemDefault(activity) + LocaleManager.resetToSystemDefault(activity, localeUseCases) activity.recreate() with(controller) { LocaleManager.updateBaseConfiguration(activity, selectedLocale) @@ -114,8 +127,9 @@ class LocaleSettingsControllerTest { @Test fun `set the default locale as the new locale`() { val selectedLocale = Locale("en", "UK") + every { localeUseCases.notifyLocaleChanged } returns mockk() every { localeSettingsStore.state } returns mockState.copy(localeList = listOf(selectedLocale)) - every { LocaleManager.resetToSystemDefault(activity) } just Runs + every { LocaleManager.resetToSystemDefault(activity, localeUseCases) } just Runs with(controller) { every { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } just Runs } @@ -123,7 +137,7 @@ class LocaleSettingsControllerTest { controller.handleDefaultLocaleSelected() verify { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) } - verify { LocaleManager.resetToSystemDefault(activity) } + verify { LocaleManager.resetToSystemDefault(activity, localeUseCases) } verify { activity.recreate() } with(controller) { verify { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 564238efa..6cf291a80 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 = "74.0.20210322143147" + const val VERSION = "74.0.20210323143308" } From 90fea8ba5e714b985b87119530ef27b6e8c58c79 Mon Sep 17 00:00:00 2001 From: mcarare Date: Tue, 23 Mar 2021 16:24:39 +0200 Subject: [PATCH 010/315] For #17790: Remove app from recents screen on quit. --- .../mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuit.kt | 2 +- .../fenix/settings/deletebrowsingdata/DeleteAndQuitTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuit.kt b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuit.kt index e5fe0ac42..d7f8a6d6e 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuit.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuit.kt @@ -49,7 +49,7 @@ fun deleteAndQuit(activity: Activity, coroutineScope: CoroutineScope, snackbar: snackbar?.dismiss() - activity.finish() + activity.finishAndRemoveTask() } } diff --git a/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuitTest.kt b/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuitTest.kt index 6164cf932..47a76456a 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuitTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteAndQuitTest.kt @@ -76,7 +76,7 @@ class DeleteAndQuitTest { verifyOrder { snackbar.show() removeAllTabsUseCases.invoke() - activity.finish() + activity.finishAndRemoveTask() } coVerify(exactly = 0) { From 3b11b9a70075869a1089ca8cf6c26802f09f53e1 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Tue, 23 Mar 2021 16:00:41 -0400 Subject: [PATCH 011/315] For #18242 - Wire up "Sync cards across devices" preference with SyncPreferenceView (#18605) --- .../creditcards/CreditCardsSettingFragment.kt | 27 +++++++++++++++++++ app/src/main/res/navigation/nav_graph.xml | 7 +++++ 2 files changed, 34 insertions(+) diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt index 57c956e99..4c2d71163 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardsSettingFragment.kt @@ -5,9 +5,14 @@ package org.mozilla.fenix.settings.creditcards import android.os.Bundle +import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceFragmentCompat +import mozilla.components.service.fxa.SyncEngine import org.mozilla.fenix.R +import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.showToolbar +import org.mozilla.fenix.settings.SyncPreferenceView +import org.mozilla.fenix.settings.requirePreference /** * "Credit cards" settings fragment displays a list of settings related to autofilling, adding and @@ -23,5 +28,27 @@ class CreditCardsSettingFragment : PreferenceFragmentCompat() { super.onResume() showToolbar(getString(R.string.preferences_credit_cards)) + + SyncPreferenceView( + syncPreference = requirePreference(R.string.pref_key_credit_cards_sync_cards_across_devices), + lifecycleOwner = viewLifecycleOwner, + accountManager = requireComponents.backgroundServices.accountManager, + syncEngine = SyncEngine.Passwords, + onSignInToSyncClicked = { + val directions = + CreditCardsSettingFragmentDirections.actionCreditCardsSettingFragmentToTurnOnSyncFragment() + findNavController().navigate(directions) + }, + onSyncStatusClicked = { + val directions = + CreditCardsSettingFragmentDirections.actionGlobalAccountSettingsFragment() + findNavController().navigate(directions) + }, + onReconnectClicked = { + val directions = + CreditCardsSettingFragmentDirections.actionGlobalAccountProblemFragment() + findNavController().navigate(directions) + } + ) } } diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 685929e00..975dd39d1 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -1008,6 +1008,13 @@ android:id="@+id/creditCardsSettingFragment" android:name="org.mozilla.fenix.settings.creditcards.CreditCardsSettingFragment" android:label="@string/preferences_credit_cards"> + From 2c23941823b5d69055867861faaad13c38b1d0cd Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Thu, 18 Mar 2021 18:58:44 +0400 Subject: [PATCH 012/315] Issue #18538: Add BrowserTabsAdapter for tabs tray --- .../fenix/tabstray/TabsTrayFragment.kt | 44 ++++++++-- .../fenix/tabstray/TabsTrayInteractor.kt | 4 +- .../fenix/tabstray/TrayPagerAdapter.kt | 15 ++-- .../mozilla/fenix/tabstray/TrayViewHolders.kt | 16 +++- .../tabstray/browser/BaseBrowserTrayList.kt | 33 ++------ .../tabstray/browser/BrowserTabsAdapter.kt | 84 +++++++++++++++++++ .../tabstray/browser/BrowserTrayInteractor.kt | 62 ++++++++++++++ .../fenix/tabstray/browser/TabsAdapter.kt | 58 +++++++++++++ .../fenix/tabstray/browser/UseCases.kt | 31 +++++++ 9 files changed, 304 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTabsAdapter.kt create mode 100644 app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt create mode 100644 app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsAdapter.kt create mode 100644 app/src/main/java/org/mozilla/fenix/tabstray/browser/UseCases.kt diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt index b0a0fc12a..2c9e6c51f 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt @@ -17,11 +17,32 @@ import com.google.android.material.tabs.TabLayout import kotlinx.android.synthetic.main.component_tabstray2.* import kotlinx.android.synthetic.main.component_tabstray2.view.* import org.mozilla.fenix.R +import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor +import org.mozilla.fenix.tabstray.browser.DefaultBrowserTrayInteractor +import org.mozilla.fenix.tabstray.browser.RemoveTabUseCaseWrapper +import org.mozilla.fenix.tabstray.browser.SelectTabUseCaseWrapper class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor { lateinit var behavior: BottomSheetBehavior + private val selectTabUseCase by lazy { + SelectTabUseCaseWrapper( + requireComponents.analytics.metrics, + requireComponents.useCases.tabsUseCases.selectTab + ) { + navigateToBrowser() + } + } + + private val removeUseCases by lazy { + RemoveTabUseCaseWrapper(requireComponents.analytics.metrics + ) { + tabRemoved(it) + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, R.style.TabTrayDialogStyle) @@ -44,7 +65,13 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setupPager(view.context, this) + val browserTrayInteractor = DefaultBrowserTrayInteractor( + this, + selectTabUseCase, + removeUseCases + ) + + setupPager(view.context, this, browserTrayInteractor) } override fun setCurrentTrayPosition(position: Int) { @@ -65,19 +92,26 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor { } } - override fun tabRemoved(sessionId: String) { + override fun tabRemoved(tabId: String) { // TODO re-implement these methods // showUndoSnackbarForTab(sessionId) // removeIfNotLastTab(sessionId) + + // Temporary + requireComponents.useCases.tabsUseCases.removeTab(tabId) } - private fun setupPager(context: Context, interactor: TabsTrayInteractor) { + private fun setupPager( + context: Context, + trayInteractor: TabsTrayInteractor, + browserInteractor: BrowserTrayInteractor + ) { tabsTray.apply { - adapter = TrayPagerAdapter(context, interactor) + adapter = TrayPagerAdapter(context, trayInteractor, browserInteractor) isUserInputEnabled = false } - tab_layout.addOnTabSelectedListener(TabLayoutObserver(interactor)) + tab_layout.addOnTabSelectedListener(TabLayoutObserver(trayInteractor)) } } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInteractor.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInteractor.kt index 6c479aad3..2544d66a3 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInteractor.kt @@ -16,7 +16,7 @@ interface TabsTrayInteractor { fun navigateToBrowser() /** - * Invoked when a tab is removed from the tabs tray with the given [sessionId]. + * Invoked when a tab is removed from the tabs tray with the given [tabId]. */ - fun tabRemoved(sessionId: String) + fun tabRemoved(tabId: String) } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt index c4ea545ae..995180413 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt @@ -7,18 +7,21 @@ package org.mozilla.fenix.tabstray import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup +import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import org.mozilla.fenix.tabstray.BrowserTabViewHolder.Companion.LAYOUT_ID_NORMAL_TAB import org.mozilla.fenix.tabstray.BrowserTabViewHolder.Companion.LAYOUT_ID_PRIVATE_TAB -import org.mozilla.fenix.tabtray.FenixTabsAdapter +import org.mozilla.fenix.tabstray.browser.BrowserTabsAdapter +import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor class TrayPagerAdapter( - context: Context, - val interactor: TabsTrayInteractor + val context: Context, + val interactor: TabsTrayInteractor, + val browserInteractor: BrowserTrayInteractor ) : RecyclerView.Adapter() { - private val normalAdapter by lazy { FenixTabsAdapter(context) } - private val privateAdapter by lazy { FenixTabsAdapter(context) } + private val normalAdapter by lazy { BrowserTabsAdapter(context, browserInteractor) } + private val privateAdapter by lazy { BrowserTabsAdapter(context, browserInteractor) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrayViewHolder { val itemView = LayoutInflater.from(parent.context).inflate(viewType, parent, false) @@ -37,7 +40,7 @@ class TrayPagerAdapter( else -> throw IllegalStateException("View type does not exist.") } - viewHolder.bind(adapter) + viewHolder.bind(adapter, GridLayoutManager(context, 1)) } override fun getItemViewType(position: Int): Int { diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TrayViewHolders.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TrayViewHolders.kt index e94226c8b..405f21fde 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TrayViewHolders.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TrayViewHolders.kt @@ -5,17 +5,22 @@ package org.mozilla.fenix.tabstray import android.view.View -import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.extensions.LayoutContainer import org.mozilla.fenix.R import org.mozilla.fenix.tabstray.browser.BaseBrowserTrayList +/** + * Base [RecyclerView.ViewHolder] for [TrayPagerAdapter] items. + */ sealed class TrayViewHolder constructor( override val containerView: View ) : RecyclerView.ViewHolder(containerView), LayoutContainer { - abstract fun bind(adapter: RecyclerView.Adapter) + abstract fun bind( + adapter: RecyclerView.Adapter, + layoutManager: RecyclerView.LayoutManager + ) } class BrowserTabViewHolder( @@ -29,8 +34,11 @@ class BrowserTabViewHolder( trayList.interactor = interactor } - override fun bind(adapter: RecyclerView.Adapter) { - trayList.layoutManager = LinearLayoutManager(itemView.context) + override fun bind( + adapter: RecyclerView.Adapter, + layoutManager: RecyclerView.LayoutManager + ) { + trayList.layoutManager = layoutManager trayList.adapter = adapter } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/BaseBrowserTrayList.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BaseBrowserTrayList.kt index caaa51108..653d756be 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/BaseBrowserTrayList.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BaseBrowserTrayList.kt @@ -7,12 +7,8 @@ package org.mozilla.fenix.tabstray.browser import android.content.Context import android.util.AttributeSet import androidx.recyclerview.widget.RecyclerView -import mozilla.components.browser.tabstray.TabsAdapter -import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.feature.tabs.tabstray.TabsFeature import mozilla.components.support.base.feature.ViewBoundFeatureWrapper -import org.mozilla.fenix.components.metrics.Event -import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.ext.components import org.mozilla.fenix.tabstray.TabsTrayInteractor import org.mozilla.fenix.tabstray.TrayItem @@ -25,7 +21,14 @@ abstract class BaseBrowserTrayList @JvmOverloads constructor( defStyleAttr: Int = 0 ) : RecyclerView(context, attrs, defStyleAttr), TrayItem { + /** + * The browser tab types we would want to show. + */ enum class BrowserTabType { NORMAL, PRIVATE } + + /** + * A configuration for classes that extend [BaseBrowserTrayList]. + */ data class Configuration(val browserTabType: BrowserTabType) abstract val configuration: Configuration @@ -71,25 +74,3 @@ abstract class BaseBrowserTrayList @JvmOverloads constructor( tabsFeature } } - -internal class SelectTabUseCaseWrapper( - private val metrics: MetricController, - private val selectTab: TabsUseCases.SelectTabUseCase, - private val onSelect: (String) -> Unit -) : TabsUseCases.SelectTabUseCase { - override fun invoke(tabId: String) { - metrics.track(Event.OpenedExistingTab) - selectTab(tabId) - onSelect(tabId) - } -} - -internal class RemoveTabUseCaseWrapper( - private val metrics: MetricController, - private val onRemove: (String) -> Unit -) : TabsUseCases.RemoveTabUseCase { - override fun invoke(sessionId: String) { - metrics.track(Event.ClosedExistingTab) - onRemove(sessionId) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTabsAdapter.kt new file mode 100644 index 000000000..ca9759fb8 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTabsAdapter.kt @@ -0,0 +1,84 @@ +/* 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.tabstray.browser + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.GridLayoutManager +import kotlinx.android.synthetic.main.tab_tray_item.view.* +import mozilla.components.browser.tabstray.TabViewHolder +import mozilla.components.browser.thumbnails.loader.ThumbnailLoader +import mozilla.components.concept.tabstray.TabsTray +import mozilla.components.support.base.observer.Observable +import mozilla.components.support.base.observer.ObserverRegistry +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.tabtray.TabTrayViewHolder + +/** + * A [RecyclerView.Adapter] for browser tabs. + */ +class BrowserTabsAdapter( + private val context: Context, + private val interactor: BrowserTrayInteractor, + private val layoutManager: (() -> GridLayoutManager)? = null, + delegate: Observable = ObserverRegistry() +) : TabsAdapter(delegate) { + + /** + * The layout types for the tabs. + */ + enum class ViewType { + LIST, + GRID + } + + private val imageLoader = ThumbnailLoader(context.components.core.thumbnailStorage) + + override fun getItemViewType(position: Int): Int { + return if (context.settings().gridTabView) { + // ViewType.GRID.ordinal + R.layout.tab_tray_grid_item + } else { + // ViewType.LIST.ordinal + R.layout.tab_tray_item + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TabViewHolder { + // TODO make this into separate view holders for each layout + // For this, we need to separate the TabTrayViewHolder as well. + // See https://github.com/mozilla-mobile/fenix/issues/18535 + val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false) + + return TabTrayViewHolder(view, imageLoader) + } + + override fun onBindViewHolder(holder: TabViewHolder, position: Int) { + super.onBindViewHolder(holder, position) + + holder.tab?.let { tab -> + if (!tab.private) { + holder.itemView.setOnLongClickListener { + interactor.onMultiSelect(true) + true + } + } else { + holder.itemView.setOnLongClickListener(null) + } + + holder.itemView.setOnClickListener { + interactor.onOpenTab(tab) + } + + holder.itemView.mozac_browser_tabstray_close.setOnClickListener { + interactor.onCloseTab(tab) + } + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt new file mode 100644 index 000000000..bf6f42b9e --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt @@ -0,0 +1,62 @@ +/* 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.tabstray.browser + +import mozilla.components.concept.tabstray.Tab +import mozilla.components.feature.tabs.TabsUseCases +import org.mozilla.fenix.tabstray.TabsTrayInteractor + +/** + * For interacting with UI that extends from [BaseBrowserTrayList] and other browser tab tray views. + */ +interface BrowserTrayInteractor { + + /** + * Select the tab. + */ + fun onOpenTab(tab: Tab) + + /** + * Close the tab. + */ + fun onCloseTab(tab: Tab) + + /** + * Enable or disable multi-select mode. + */ + fun onMultiSelect(enabled: Boolean) +} + +/** + * A default implementation of [BrowserTrayInteractor]. + */ +class DefaultBrowserTrayInteractor( + private val trayInteractor: TabsTrayInteractor, + private val selectTabUseCase: TabsUseCases.SelectTabUseCase, + private val removeUseCases: TabsUseCases.RemoveTabUseCase +) : BrowserTrayInteractor { + + /** + * See [BrowserTrayInteractor.onOpenTab]. + */ + override fun onOpenTab(tab: Tab) { + selectTabUseCase.invoke(tab.id) + trayInteractor.navigateToBrowser() + } + + /** + * See [BrowserTrayInteractor.onCloseTab]. + */ + override fun onCloseTab(tab: Tab) { + removeUseCases.invoke(tab.id) + } + + /** + * See [BrowserTrayInteractor.onMultiSelect]. + */ + override fun onMultiSelect(enabled: Boolean) { + // TODO https://github.com/mozilla-mobile/fenix/issues/18443 + } +} 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 new file mode 100644 index 000000000..c0bced601 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsAdapter.kt @@ -0,0 +1,58 @@ +/* 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.tabstray.browser + +import androidx.annotation.CallSuper +import androidx.recyclerview.widget.RecyclerView +import mozilla.components.browser.tabstray.TabViewHolder +import mozilla.components.browser.tabstray.TabsTrayStyling +import mozilla.components.concept.tabstray.Tabs +import mozilla.components.concept.tabstray.TabsTray +import mozilla.components.support.base.observer.Observable +import mozilla.components.support.base.observer.ObserverRegistry + +// The previous tabs adapter was very restrictive and required Fenix to jump through +// may hoops to access and update certain methods. An abstract adapter is easier to manage +// for Android UI APIs. +// +// TODO Let's upstream this to AC with tests. +abstract class TabsAdapter( + delegate: Observable = ObserverRegistry() +) : RecyclerView.Adapter(), TabsTray, Observable by delegate { + private var tabs: Tabs? = null + + var styling: TabsTrayStyling = TabsTrayStyling() + + override fun getItemCount(): Int = tabs?.list?.size ?: 0 + + @CallSuper + override fun updateTabs(tabs: Tabs) { + this.tabs = tabs + + notifyObservers { onTabsUpdated() } + } + + @CallSuper + override fun onBindViewHolder(holder: TabViewHolder, position: Int) { + val tabs = tabs ?: return + + holder.bind(tabs.list[position], isTabSelected(tabs, position), styling, this) + } + + 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) +} diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/UseCases.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/UseCases.kt new file mode 100644 index 000000000..7dbfaa457 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/UseCases.kt @@ -0,0 +1,31 @@ +/* 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.tabstray.browser + +import mozilla.components.feature.tabs.TabsUseCases +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.components.metrics.MetricController + +class SelectTabUseCaseWrapper( + private val metrics: MetricController, + private val selectTab: TabsUseCases.SelectTabUseCase, + private val onSelect: (String) -> Unit +) : TabsUseCases.SelectTabUseCase { + override fun invoke(tabId: String) { + metrics.track(Event.OpenedExistingTab) + selectTab(tabId) + onSelect(tabId) + } +} + +class RemoveTabUseCaseWrapper( + private val metrics: MetricController, + private val onRemove: (String) -> Unit +) : TabsUseCases.RemoveTabUseCase { + override fun invoke(sessionId: String) { + metrics.track(Event.ClosedExistingTab) + onRemove(sessionId) + } +} From cd0efaca408a3ffabb2b879b9e53af5df6340434 Mon Sep 17 00:00:00 2001 From: Mozilla L10n Automation Bot Date: Wed, 24 Mar 2021 00:03:17 +0000 Subject: [PATCH 013/315] Import l10n. --- app/src/main/res/values-bg/strings.xml | 8 +++++++- app/src/main/res/values-ca/strings.xml | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 3237b3f84..bfcec8041 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -21,6 +21,10 @@ Поверителните раздели ще бъдат показани тук. + + Baidu + + JD 1 отворен раздел. Докоснете за превключване на раздели. @@ -99,7 +103,7 @@ Към настройки - Отхвърляне + Прекратяване @@ -978,6 +982,8 @@ Разделите са затворени Разделите са затворени! + + Преглед Поверителният раздел е затворен diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index aa6013a6b..7ef4e91a8 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -180,6 +180,8 @@ Aparença + + Personalitza la vista de lectura No s’ha pogut connectar. No es reconeix l’esquema d’URL. From fc220da3365d2a9700008db54cc78e9f9be0cbd6 Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Wed, 24 Mar 2021 15:33:33 +0000 Subject: [PATCH 014/315] Update Android Components version to 75.0.20210324143047. --- 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 6cf291a80..ff3527b9b 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 = "74.0.20210323143308" + const val VERSION = "75.0.20210324143047" } From 34a7bc0baa49002bb53d00c621104778a76c4996 Mon Sep 17 00:00:00 2001 From: Roger Yang Date: Wed, 24 Mar 2021 14:31:39 -0400 Subject: [PATCH 015/315] For #17644: Record when user taps on a add-on's setting (#18504) --- app/metrics.yaml | 17 ++++++++++ .../addons/InstalledAddonDetailsFragment.kt | 4 +++ .../mozilla/fenix/components/metrics/Event.kt | 5 +++ .../components/metrics/GleanMetricsService.kt | 4 +++ .../metrics/GleanMetricsServiceTest.kt | 31 +++++++++++++++++-- docs/metrics.md | 1 + 6 files changed, 60 insertions(+), 2 deletions(-) diff --git a/app/metrics.yaml b/app/metrics.yaml index 2e311c746..7a89e0e93 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -3938,6 +3938,23 @@ addons: notification_emails: - fenix-core@mozilla.com expires: "2021-07-01" + open_addon_setting: + type: event + description: | + A user opened an add-on's setting + extra_keys: + addon_id: + description: | + The id of the add-on that was interacted with + bugs: + - https://github.com/mozilla-mobile/fenix/issues/17644 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/18504 + data_sensitivity: + - interaction + notification_emails: + - fenix-core@mozilla.com + expires: "2022-08-01" has_installed_addons: type: boolean description: | diff --git a/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt index c154aa4f9..bb051e9e5 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt @@ -24,6 +24,7 @@ import mozilla.components.feature.addons.ui.translateName import org.mozilla.fenix.GleanMetrics.Addons import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.ext.runIfFragmentIsAttached @@ -196,6 +197,9 @@ class InstalledAddonDetailsFragment : Fragment() { view.settings.apply { isVisible = shouldSettingsBeVisible() setOnClickListener { + requireContext().components.analytics.metrics.track( + Event.AddonOpenSetting(addon.id) + ) val settingUrl = addon.installedState?.optionsPageUrl ?: return@setOnClickListener val directions = if (addon.installedState?.openOptionsPageInTab == true) { val components = it.context.components 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 c6d17dfed..d839459fc 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 @@ -325,6 +325,11 @@ sealed class Event { get() = hashMapOf(Addons.openAddonInToolbarMenuKeys.addonId to addonId) } + data class AddonOpenSetting(val addonId: String) : Event() { + override val extras: Map? + get() = hashMapOf(Addons.openAddonSettingKeys.addonId to addonId) + } + data class TipDisplayed(val identifier: String) : Event() { override val extras: Map? get() = hashMapOf(Tip.displayedKeys.identifier to identifier) 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 6ae3601b3..45eb024bb 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 @@ -586,6 +586,10 @@ private val Event.wrapper: EventWrapper<*>? { Addons.openAddonInToolbarMenu.record(it) }, { Addons.openAddonInToolbarMenuKeys.valueOf(it) } ) + is Event.AddonOpenSetting -> EventWrapper( + { Addons.openAddonSetting.record(it) }, + { Addons.openAddonSettingKeys.valueOf(it) } + ) is Event.TipDisplayed -> EventWrapper( { Tip.displayed.record(it) }, { Tip.displayedKeys.valueOf(it) } diff --git a/app/src/test/java/org/mozilla/fenix/components/metrics/GleanMetricsServiceTest.kt b/app/src/test/java/org/mozilla/fenix/components/metrics/GleanMetricsServiceTest.kt index 2cb344365..9afcb980a 100644 --- a/app/src/test/java/org/mozilla/fenix/components/metrics/GleanMetricsServiceTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/GleanMetricsServiceTest.kt @@ -159,7 +159,7 @@ class GleanMetricsServiceTest { } @Test - fun `bookmark events is correctly recorded`() { + fun `bookmark events are correctly recorded`() { assertFalse(BookmarksManagement.open.testHasValue()) gleanService.track(Event.OpenedBookmark) assertTrue(BookmarksManagement.open.testHasValue()) @@ -214,7 +214,7 @@ class GleanMetricsServiceTest { } @Test - fun `History events is correctly recorded`() { + fun `History events are correctly recorded`() { assertFalse(History.openedItemInNewTab.testHasValue()) gleanService.track(Event.HistoryOpenedInNewTab) assertTrue(History.openedItemInNewTab.testHasValue()) @@ -231,4 +231,31 @@ class GleanMetricsServiceTest { gleanService.track(Event.HistoryOpenedInPrivateTabs) assertTrue(History.openedItemsInPrivateTabs.testHasValue()) } + + @Test + fun `Addon events are correctly recorded`() { + assertFalse(Addons.openAddonsInSettings.testHasValue()) + gleanService.track(Event.AddonsOpenInSettings) + assertTrue(Addons.openAddonsInSettings.testHasValue()) + + assertFalse(Addons.openAddonInToolbarMenu.testHasValue()) + gleanService.track(Event.AddonsOpenInToolbarMenu("123")) + assertTrue(Addons.openAddonInToolbarMenu.testHasValue()) + var events = Addons.openAddonInToolbarMenu.testGetValue() + assertEquals(1, events.size) + assertEquals("addons", events[0].category) + assertEquals("open_addon_in_toolbar_menu", events[0].name) + assertEquals(1, events[0].extra!!.size) + assertEquals("123", events[0].extra!!["addon_id"]) + + assertFalse(Addons.openAddonSetting.testHasValue()) + gleanService.track(Event.AddonOpenSetting("123")) + assertTrue(Addons.openAddonSetting.testHasValue()) + events = Addons.openAddonSetting.testGetValue() + assertEquals(1, events.size) + assertEquals("addons", events[0].category) + assertEquals("open_addon_setting", events[0].name) + assertEquals(1, events[0].extra!!.size) + assertEquals("123", events[0].extra!!["addon_id"]) + } } diff --git a/docs/metrics.md b/docs/metrics.md index 63598cc4a..f96f3db54 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -55,6 +55,7 @@ In addition to those built-in metrics, the following metrics are added to the pi | about_page.privacy_notice_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Privacy notice" item from About page |[mozilla-mobile/fenix#8047](https://github.com/mozilla-mobile/fenix/pull/8047), [mozilla-mobile/fenix#13958](https://github.com/mozilla-mobile/fenix/pull/13958#issuecomment-676857877), [mozilla-mobile/fenix#18143](https://github.com/mozilla-mobile/fenix/pull/18143)||2021-07-01 |2 | | about_page.support_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Support" item from About page |[mozilla-mobile/fenix#8047](https://github.com/mozilla-mobile/fenix/pull/8047), [mozilla-mobile/fenix#13958](https://github.com/mozilla-mobile/fenix/pull/13958#issuecomment-676857877), [mozilla-mobile/fenix#18143](https://github.com/mozilla-mobile/fenix/pull/18143)||2021-07-01 |2 | | addons.open_addon_in_toolbar_menu |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user interacted with an installed add-on in the toolbar menu |[mozilla-mobile/fenix#8318](https://github.com/mozilla-mobile/fenix/pull/8318), [mozilla-mobile/fenix#13958](https://github.com/mozilla-mobile/fenix/pull/13958#issuecomment-676857877), [mozilla-mobile/fenix#18143](https://github.com/mozilla-mobile/fenix/pull/18143)|
  • addon_id: The id of the add-on that was interacted with in the toolbar menu
|2021-07-01 |2 | +| addons.open_addon_setting |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened an add-on's setting |[mozilla-mobile/fenix#18504](https://github.com/mozilla-mobile/fenix/pull/18504)|
  • addon_id: The id of the add-on that was interacted with
|2022-08-01 |2 | | addons.open_addons_in_settings |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user accessed "Add-ons" from the Settings |[mozilla-mobile/fenix#8318](https://github.com/mozilla-mobile/fenix/pull/8318), [mozilla-mobile/fenix#13958](https://github.com/mozilla-mobile/fenix/pull/13958#issuecomment-676857877), [mozilla-mobile/fenix#18143](https://github.com/mozilla-mobile/fenix/pull/18143)||2021-07-01 |2 | | android_keystore_experiment.experiment_failure |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Records an instance of an unexpected failure during the experiment |[mozilla-mobile/fenix#18333](https://github.com/mozilla-mobile/fenix/pull/18333#pullrequestreview-612447395)|
  • failure_exception: Exception class associated with an unexpected failure of this experiment, not caught by the other failure handlers.
|2021-09-01 |1 | | android_keystore_experiment.get_failure |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Unexpected failure when trying to read from secure prefs. |[mozilla-mobile/fenix#18333](https://github.com/mozilla-mobile/fenix/pull/18333#pullrequestreview-612447395)|
  • failure_exception: Exception class associated with an unexpected failure of this experiment.
|2021-09-01 |1 | From 246c192de377fa180029604846bb3497c4770dd9 Mon Sep 17 00:00:00 2001 From: Aaron Train Date: Wed, 24 Mar 2021 15:33:17 -0400 Subject: [PATCH 016/315] Closes #18623: Fix Gradle task name in gradlewbuild.py (#18624) --- .../java/org/mozilla/fenix/syncintegration/gradlewbuild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/syncintegration/gradlewbuild.py b/app/src/androidTest/java/org/mozilla/fenix/syncintegration/gradlewbuild.py index d4b325c00..37e03bee0 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/syncintegration/gradlewbuild.py +++ b/app/src/androidTest/java/org/mozilla/fenix/syncintegration/gradlewbuild.py @@ -21,7 +21,7 @@ class GradlewBuild(object): # Change path accordingly to go to root folder to run gradlew os.chdir('../../../../../../../..') - cmd = './gradlew ' + 'app:connectedGeckoNightlyDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.mozilla.fenix.syncintegration.SyncIntegrationTest#{}'.format(identifier) + cmd = './gradlew ' + 'app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.mozilla.fenix.syncintegration.SyncIntegrationTest#{}'.format(identifier) self.logger.info('Running cmd: {}'.format(cmd)) From 869c99afaa71da969be39d4f04efda77146fa6b8 Mon Sep 17 00:00:00 2001 From: Arturo Mejia Date: Thu, 18 Mar 2021 23:25:20 -0400 Subject: [PATCH 017/315] For #15372 Optimize the order and messages of onboarding cards --- .../java/org/mozilla/fenix/ui/SmokeTest.kt | 16 ++-- .../fenix/ui/robots/HomeScreenRobot.kt | 75 ++++++---------- ...sSubMenuEnhancedTrackingProtectionRobot.kt | 14 +-- .../java/org/mozilla/fenix/ui/util/Strings.kt | 9 ++ .../home/sessioncontrol/SessionControlView.kt | 16 ++-- .../OnboardingManualSignInViewHolder.kt | 12 +-- .../OnboardingTrackingProtectionViewHolder.kt | 27 +----- .../fenix/onboarding/OnboardingController.kt | 22 ----- .../fenix/onboarding/OnboardingInteractor.kt | 14 --- .../ic_onboarding_avatar_anonymous_large.xml | 4 +- .../res/layout/onboarding_manual_signin.xml | 36 ++++---- .../res/layout/onboarding_theme_picker.xml | 2 +- .../onboarding_toolbar_position_picker.xml | 89 +++++++++---------- .../layout/onboarding_tracking_protection.xml | 20 ++--- app/src/main/res/values/strings.xml | 38 ++++---- .../xml/tracking_protection_preferences.xml | 4 +- .../OnboardingManualSignInViewHolderTest.kt | 11 +-- ...oardingTrackingProtectionViewHolderTest.kt | 6 +- 18 files changed, 146 insertions(+), 269 deletions(-) create mode 100644 app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt delete mode 100644 app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt delete mode 100644 app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt 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 63b588286..82c9fa4f0 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -35,6 +35,7 @@ import org.mozilla.fenix.ui.robots.enhancedTrackingProtection import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar import org.mozilla.fenix.ui.robots.tabDrawer +import org.mozilla.fenix.ui.util.STRING_ONBOARDING_TRACKING_PROTECTION_HEADER /** * Test Suite that contains tests defined as part of the Smoke and Sanity check defined in Test rail. @@ -125,13 +126,9 @@ class SmokeTest { verifyStartSyncHeader() verifyAccountsSignInButton() - // Intro to other sections - verifyGetToKnowHeader() - - // Automatic privacy - scrollToElementByText("Automatic privacy") + // Always-on privacy + scrollToElementByText(STRING_ONBOARDING_TRACKING_PROTECTION_HEADER) verifyAutomaticPrivacyHeader() - verifyTrackingProtectionToggle() verifyAutomaticPrivacyText() // Choose your theme @@ -142,11 +139,7 @@ class SmokeTest { verifyLightThemeDescription() verifyLightThemeToggle() - // Browse privately - verifyBrowsePrivatelyHeader() - verifyBrowsePrivatelyText() - - // Take a position + // Pick your toolbar placement verifyTakePositionHeader() verifyTakePositionElements() @@ -161,6 +154,7 @@ class SmokeTest { } @Test + @Ignore("https://github.com/mozilla-mobile/fenix/issues/18603") // Verifies the functionality of the onboarding Start Browsing button fun startBrowsingButtonTest() { homeScreen { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt index 2db81496c..cc649577d 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt @@ -54,6 +54,9 @@ import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.matchers.hasItem import org.mozilla.fenix.helpers.withBitmapDrawable +import org.mozilla.fenix.ui.util.STRING_ONBOARDING_ACCOUNT_SIGN_IN_HEADER +import org.mozilla.fenix.ui.util.STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER +import org.mozilla.fenix.ui.util.STRING_ONBOARDING_TRACKING_PROTECTION_HEADER /** * Implementation of Robot Pattern for the home screen menu. @@ -85,7 +88,6 @@ class HomeScreenRobot { fun verifyStartSyncHeader() = assertStartSyncHeader() fun verifyAccountsSignInButton() = assertAccountsSignInButton() - fun verifyGetToKnowHeader() = assertGetToKnowHeader() fun verifyChooseThemeHeader() = assertChooseThemeHeader() fun verifyChooseThemeText() = assertChooseThemeText() fun verifyLightThemeToggle() = assertLightThemeToggle() @@ -95,18 +97,13 @@ class HomeScreenRobot { fun verifyAutomaticThemeToggle() = assertAutomaticThemeToggle() fun verifyAutomaticThemeDescription() = assertAutomaticThemeDescription() fun verifyAutomaticPrivacyHeader() = assertAutomaticPrivacyHeader() - fun verifyTrackingProtectionToggle() = assertTrackingProtectionToggle() - fun verifyAutomaticPrivacyText() = assertAutomaticPrivacyText() + fun verifyAutomaticPrivacyText() = assertAlwaysPrivacyText() - // Browse privately - fun verifyBrowsePrivatelyHeader() = assertBrowsePrivatelyHeader() - fun verifyBrowsePrivatelyText() = assertBrowsePrivatelyText() - - // Take a position - fun verifyTakePositionHeader() = assertTakePositionheader() + // Pick your toolbar placement + fun verifyTakePositionHeader() = assertTakePlacementHeader() fun verifyTakePositionElements() { - assertTakePositionBottomRadioButton() - assertTakePositionTopRadioButton() + assertTakePlacementBottomRadioButton() + assertTakePacementTopRadioButton() } // Your privacy @@ -549,18 +546,15 @@ private fun assertWelcomeHeader() = onView(allOf(withText("Welcome to ${appContext.appName}!"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertStartSyncHeader() = - onView(allOf(withText("Start syncing bookmarks, passwords, and more with your Firefox account."))) +private fun assertStartSyncHeader() { + scrollToElementByText(STRING_ONBOARDING_ACCOUNT_SIGN_IN_HEADER) + onView(allOf(withText(R.string.onboarding_account_sign_in_header_1))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - +} private fun assertAccountsSignInButton() = onView(ViewMatchers.withResourceName("fxa_sign_in_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertGetToKnowHeader() = - onView(allOf(withText("Get to know ${appContext.appName}"))) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - private fun assertChooseThemeHeader() { scrollToElementByText("Choose your theme") onView(withText("Choose your theme")) @@ -568,7 +562,7 @@ private fun assertChooseThemeHeader() { } private fun assertChooseThemeText() { scrollToElementByText("Choose your theme") - onView(allOf(withText("Save some battery and your eyesight by enabling dark mode."))) + onView(allOf(withText("Save some battery and your eyesight with dark mode."))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } @@ -608,40 +602,23 @@ private fun assertAutomaticThemeDescription() { } private fun assertAutomaticPrivacyHeader() { - scrollToElementByText("Automatic privacy") - onView(allOf(withText("Automatic privacy"))) + scrollToElementByText(STRING_ONBOARDING_TRACKING_PROTECTION_HEADER) + onView(allOf(withText(STRING_ONBOARDING_TRACKING_PROTECTION_HEADER))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertTrackingProtectionToggle() { - scrollToElementByText("Automatic privacy") - onView(withId(R.id.tracking_protection_toggle)) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -} - -private fun assertAutomaticPrivacyText() { - scrollToElementByText("Automatic privacy") +private fun assertAlwaysPrivacyText() { + scrollToElementByText(STRING_ONBOARDING_TRACKING_PROTECTION_HEADER) onView( allOf( withText( - "Privacy and security settings block trackers, malware, and companies that follow you." + R.string.onboarding_tracking_protection_description_3 ) ) ) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertBrowsePrivatelyHeader() { - scrollToElementByText("Browse privately") - onView(allOf(withText("Browse privately"))) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -} - -private fun assertBrowsePrivatelyText() { - scrollToElementByText("Browse privately") - onView(allOf(withText(containsString("Update your private browsing settings.")))) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -} private fun assertYourPrivacyHeader() { scrollToElementByText("Your privacy") onView(allOf(withText("Your privacy"))) @@ -672,21 +649,21 @@ private fun assertStartBrowsingButton() { .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -// Take a position -private fun assertTakePositionheader() { - scrollToElementByText("Take a position") - onView(allOf(withText("Take a position"))) +// Pick your toolbar placement +private fun assertTakePlacementHeader() { + scrollToElementByText(STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER) + onView(allOf(withText(STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertTakePositionTopRadioButton() { - scrollToElementByText("Take a position") +private fun assertTakePacementTopRadioButton() { + scrollToElementByText(STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER) onView(ViewMatchers.withResourceName("toolbar_top_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertTakePositionBottomRadioButton() { - scrollToElementByText("Take a position") +private fun assertTakePlacementBottomRadioButton() { + scrollToElementByText(STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER) onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuEnhancedTrackingProtectionRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuEnhancedTrackingProtectionRobot.kt index 14e7b0a8e..e3fe7d6fa 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuEnhancedTrackingProtectionRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuEnhancedTrackingProtectionRobot.kt @@ -143,16 +143,13 @@ private fun assertEnhancedTrackingProtectionOptions() { onView(withText("Standard (default)")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - val stdText = "Blocks fewer trackers. Pages will load normally." - onView(withText(stdText)) + onView(withText(org.mozilla.fenix.R.string.preference_enhanced_tracking_protection_standard_description_4)) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) onView(withText("Strict")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - val strictText = - "Blocks more trackers, ads, and popups. Pages load faster, but some functionality might not work." - onView(withText(strictText)) + onView(withText(org.mozilla.fenix.R.string.preference_enhanced_tracking_protection_strict_description_3)) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) onView(withText("Custom")) @@ -168,16 +165,13 @@ private fun assertEnhancedTrackingProtectionOptionsGrayedOut() { onView(withText("Standard (default)")) .check(matches(not(isEnabled(true)))) - val stdText = "Blocks fewer trackers. Pages will load normally." - onView(withText(stdText)) + onView(withText(org.mozilla.fenix.R.string.preference_enhanced_tracking_protection_standard_description_4)) .check(matches(not(isEnabled(true)))) onView(withText("Strict")) .check(matches(not(isEnabled(true)))) - val strictText = - "Blocks more trackers, ads, and popups. Pages load faster, but some functionality might not work." - onView(withText(strictText)) + onView(withText(org.mozilla.fenix.R.string.preference_enhanced_tracking_protection_strict_description_3)) .check(matches(not(isEnabled(true)))) onView(withText("Custom")) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt new file mode 100644 index 000000000..3550cf1bc --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt @@ -0,0 +1,9 @@ +/* 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.ui.util + +const val STRING_ONBOARDING_ACCOUNT_SIGN_IN_HEADER = "Sync Firefox between devices" +const val STRING_ONBOARDING_TRACKING_PROTECTION_HEADER = "Always-on privacy" +const val STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER = "Pick your toolbar placement" 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 3258fb31d..1f22ca064 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 @@ -12,7 +12,6 @@ import androidx.recyclerview.widget.RecyclerView import kotlinx.android.extensions.LayoutContainer import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.top.sites.TopSite -import org.mozilla.fenix.R import org.mozilla.fenix.components.tips.Tip import org.mozilla.fenix.ext.components import org.mozilla.fenix.home.HomeFragmentState @@ -71,6 +70,13 @@ private fun privateModeAdapterItems() = listOf(AdapterItem.PrivateBrowsingDescri private fun onboardingAdapterItems(onboardingState: OnboardingState): List { val items: MutableList = mutableListOf(AdapterItem.OnboardingHeader) + items.addAll( + listOf( + AdapterItem.OnboardingThemePicker, + AdapterItem.OnboardingToolbarPositionPicker, + AdapterItem.OnboardingTrackingProtection + ) + ) // Customize FxA items based on where we are with the account state: items.addAll( when (onboardingState) { @@ -90,14 +96,6 @@ private fun onboardingAdapterItems(onboardingState: OnboardingState): List - updateTrackingProtectionSetting(isChecked) - updateRadioGroupState(isChecked) - } - } - - setupRadioGroup(trackingProtectionToggle.isChecked) - updateRadioGroupState(trackingProtectionToggle.isChecked) + val isTrackingProtectionEnabled = view.context.settings().shouldUseTrackingProtection + setupRadioGroup(isTrackingProtectionEnabled) + updateRadioGroupState(isTrackingProtectionEnabled) } private fun setupRadioGroup(isChecked: Boolean) { @@ -74,15 +64,6 @@ class OnboardingTrackingProtectionViewHolder(view: View) : RecyclerView.ViewHold strictTrackingProtection.isEnabled = isChecked } - private fun updateTrackingProtectionSetting(enabled: Boolean) { - itemView.context.settings().shouldUseTrackingProtection = enabled - with(itemView.context.components) { - val policy = core.trackingProtectionPolicyFactory.createTrackingProtectionPolicy() - useCases.settingsUseCases.updateTrackingProtection.invoke(policy) - useCases.sessionUseCases.reload.invoke() - } - } - private fun updateTrackingProtectionPolicy() { itemView.context?.components?.let { val policy = it.core.trackingProtectionPolicyFactory diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt deleted file mode 100644 index 3e1945103..000000000 --- a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* 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.content.Context -import org.mozilla.fenix.BrowserDirection -import org.mozilla.fenix.HomeActivity -import org.mozilla.fenix.settings.SupportUtils - -class OnboardingController( - private val context: Context -) { - fun handleLearnMoreClicked() { - (context as HomeActivity).openToBrowserAndLoad( - searchTermOrURL = SupportUtils.getFirefoxAccountSumoUrl(), - newTab = true, - from = BrowserDirection.FromHome - ) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt deleted file mode 100644 index ad11d459c..000000000 --- a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* 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 - -class OnboardingInteractor(private val onboardingController: OnboardingController) { - - /** - * Called when the user clicks the learn more link - * @param url the url the suggestion was providing - */ - fun onLearnMoreClicked() = onboardingController.handleLearnMoreClicked() -} diff --git a/app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml b/app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml index 422897fd9..078d9b0ec 100644 --- a/app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml +++ b/app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml @@ -8,9 +8,9 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/layout/onboarding_manual_signin.xml b/app/src/main/res/layout/onboarding_manual_signin.xml index c1503c97b..dbbcadd16 100644 --- a/app/src/main/res/layout/onboarding_manual_signin.xml +++ b/app/src/main/res/layout/onboarding_manual_signin.xml @@ -7,7 +7,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/onboarding_card" - style="@style/OnboardingCardDark" + style="@style/OnboardingCardLightWithPadding" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> @@ -26,37 +26,31 @@ android:id="@+id/header_text" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textAppearance="@style/Header16TextStyle" + android:textAppearance="@style/HeaderTextStyle" android:lineSpacingExtra="8sp" - android:textColor="@color/neutral_text" - app:drawableTint="@color/white_color" + android:layout_marginTop="10dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/avatar_icon" android:layout_marginStart="52dp" - tools:text="@string/onboarding_account_sign_in_header" - /> + tools:text="@string/onboarding_account_sign_in_header_1" /> - + android:layout_marginTop="14dp" + android:text="@string/onboarding_manual_sign_in_description" + android:textAppearance="@style/Body14TextStyle" + app:layout_constraintStart_toStartOf="@id/avatar_icon" + app:layout_constraintTop_toBottomOf="@id/avatar_icon" />