From c119070e213ac2f835967f045d13bca36db972b9 Mon Sep 17 00:00:00 2001 From: Kainalu Hagiwara Date: Mon, 10 Aug 2020 16:25:07 -0700 Subject: [PATCH 001/128] For #13030 - Use material design animation values for swipe to switch tabs. --- app/build.gradle | 1 - .../fenix/browser/ToolbarGestureHandler.kt | 133 ++++++++---------- buildSrc/src/main/java/Dependencies.kt | 2 - 3 files changed, 55 insertions(+), 81 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0fc4e940c..5055bc680 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -428,7 +428,6 @@ dependencies { implementation Deps.androidx_lifecycle_viewmodel implementation Deps.androidx_core implementation Deps.androidx_core_ktx - implementation Deps.androidx_dynamic_animation implementation Deps.androidx_transition implementation Deps.androidx_work_ktx implementation Deps.google_material diff --git a/app/src/main/java/org/mozilla/fenix/browser/ToolbarGestureHandler.kt b/app/src/main/java/org/mozilla/fenix/browser/ToolbarGestureHandler.kt index cd507391b..a7bfe9d4d 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/ToolbarGestureHandler.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/ToolbarGestureHandler.kt @@ -6,19 +6,19 @@ package org.mozilla.fenix.browser import android.animation.Animator import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator import android.app.Activity import android.graphics.PointF import android.graphics.Rect -import android.util.TypedValue import android.view.View import android.view.ViewConfiguration import androidx.annotation.Dimension import androidx.annotation.Dimension.DP +import androidx.core.animation.doOnEnd import androidx.core.graphics.contains import androidx.core.graphics.toPoint import androidx.core.view.isVisible -import androidx.dynamicanimation.animation.DynamicAnimation -import androidx.dynamicanimation.animation.FlingAnimation +import androidx.interpolator.view.animation.LinearOutSlowInInterpolator import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.support.ktx.android.util.dpToPx @@ -61,11 +61,6 @@ class ToolbarGestureHandler( private val touchSlop = ViewConfiguration.get(activity).scaledTouchSlop private val minimumFlingVelocity = ViewConfiguration.get(activity).scaledMinimumFlingVelocity - private val defaultVelocity = TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - MINIMUM_ANIMATION_VELOCITY, - activity.resources.displayMetrics - ) private var gestureDirection = GestureDirection.LEFT_TO_RIGHT @@ -143,25 +138,12 @@ class ToolbarGestureHandler( ) { val destination = getDestination() if (destination is Destination.Tab && isGestureComplete(velocityX)) { - animateToNextTab(velocityX, destination.session) + animateToNextTab(destination.session) } else { animateCanceledGesture(velocityX) } } - private fun createFlingAnimation( - view: View, - minValue: Float, - maxValue: Float, - startVelocity: Float - ): FlingAnimation = - FlingAnimation(view, DynamicAnimation.TRANSLATION_X).apply { - setMinValue(minValue) - setMaxValue(maxValue) - setStartVelocity(startVelocity) - friction = ViewConfiguration.getScrollFriction() - } - private fun getDestination(): Destination { val isLtr = activity.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR val currentSession = sessionManager.selectedSession ?: return Destination.None @@ -234,73 +216,59 @@ class ToolbarGestureHandler( abs(velocityX) >= minimumFlingVelocity) } - private fun getVelocityFromFling(velocityX: Float): Float { - return max(abs(velocityX), defaultVelocity) + private fun getAnimator(finalContextX: Float, duration: Long): ValueAnimator { + return ValueAnimator.ofFloat(contentLayout.translationX, finalContextX).apply { + this.duration = duration + this.interpolator = LinearOutSlowInInterpolator() + addUpdateListener { animator -> + val value = animator.animatedValue as Float + contentLayout.translationX = value + tabPreview.translationX = when (gestureDirection) { + GestureDirection.RIGHT_TO_LEFT -> value + windowWidth + previewOffset + GestureDirection.LEFT_TO_RIGHT -> value - windowWidth - previewOffset + } + } + } } - private fun animateToNextTab(velocityX: Float, session: Session) { + private fun animateToNextTab(session: Session) { val browserFinalXCoordinate: Float = when (gestureDirection) { GestureDirection.RIGHT_TO_LEFT -> -windowWidth.toFloat() - previewOffset GestureDirection.LEFT_TO_RIGHT -> windowWidth.toFloat() + previewOffset } - val animationVelocity = when (gestureDirection) { - GestureDirection.RIGHT_TO_LEFT -> -getVelocityFromFling(velocityX) - GestureDirection.LEFT_TO_RIGHT -> getVelocityFromFling(velocityX) - } // Finish animating the contentLayout off screen and tabPreview on screen - createFlingAnimation( - view = contentLayout, - minValue = min(0f, browserFinalXCoordinate), - maxValue = max(0f, browserFinalXCoordinate), - startVelocity = animationVelocity - ).addUpdateListener { _, value, _ -> - tabPreview.translationX = when (gestureDirection) { - GestureDirection.RIGHT_TO_LEFT -> value + windowWidth + previewOffset - GestureDirection.LEFT_TO_RIGHT -> value - windowWidth - previewOffset + getAnimator(browserFinalXCoordinate, FINISHED_GESTURE_ANIMATION_DURATION).apply { + doOnEnd { + contentLayout.translationX = 0f + sessionManager.select(session) + + // Fade out the tab preview to prevent flickering + val shortAnimationDuration = + activity.resources.getInteger(android.R.integer.config_shortAnimTime) + tabPreview.animate() + .alpha(0f) + .setDuration(shortAnimationDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + tabPreview.isVisible = false + } + }) } - }.addEndListener { _, _, _, _ -> - contentLayout.translationX = 0f - sessionManager.select(session) - - // Fade out the tab preview to prevent flickering - val shortAnimationDuration = - activity.resources.getInteger(android.R.integer.config_shortAnimTime) - tabPreview.animate() - .alpha(0f) - .setDuration(shortAnimationDuration.toLong()) - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator?) { - tabPreview.isVisible = false - } - }) }.start() } - private fun animateCanceledGesture(gestureVelocity: Float) { - val velocity = if (getDestination() is Destination.None) { - defaultVelocity + private fun animateCanceledGesture(velocityX: Float) { + val duration = if (abs(velocityX) >= minimumFlingVelocity) { + CANCELED_FLING_ANIMATION_DURATION } else { - getVelocityFromFling(gestureVelocity) - }.let { v -> - when (gestureDirection) { - GestureDirection.RIGHT_TO_LEFT -> v - GestureDirection.LEFT_TO_RIGHT -> -v - } + CANCELED_GESTURE_ANIMATION_DURATION } - createFlingAnimation( - view = contentLayout, - minValue = min(0f, contentLayout.translationX), - maxValue = max(0f, contentLayout.translationX), - startVelocity = velocity - ).addUpdateListener { _, value, _ -> - tabPreview.translationX = when (gestureDirection) { - GestureDirection.RIGHT_TO_LEFT -> value + windowWidth + previewOffset - GestureDirection.LEFT_TO_RIGHT -> value - windowWidth - previewOffset + getAnimator(0f, duration).apply { + doOnEnd { + tabPreview.isVisible = false } - }.addEndListener { _, _, _, _ -> - tabPreview.isVisible = false }.start() } @@ -337,15 +305,24 @@ class ToolbarGestureHandler( private const val OVERSCROLL_HIDE_PERCENT = 0.20 /** - * The speed of the fling animation (in dp per second). + * The size of the gap between the tab preview and content layout. */ @Dimension(unit = DP) - private const val MINIMUM_ANIMATION_VELOCITY = 1500f + private const val PREVIEW_OFFSET = 48 /** - * The size of the gap between the tab preview and content layout. + * Animation duration when switching to another tab */ - @Dimension(unit = DP) - private const val PREVIEW_OFFSET = 48 + private const val FINISHED_GESTURE_ANIMATION_DURATION = 250L + + /** + * Animation duration gesture is canceled due to the swipe not being far enough + */ + private const val CANCELED_GESTURE_ANIMATION_DURATION = 200L + + /** + * Animation duration gesture is canceled due to a swipe in the opposite direction + */ + private const val CANCELED_FLING_ANIMATION_DURATION = 150L } } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 40933b3c0..8ba27fd3e 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -27,7 +27,6 @@ object Versions { const val androidx_paging = "2.1.0" const val androidx_transition = "1.3.0" const val androidx_work = "2.2.0" - const val androidx_dynamic_animation = "1.0.0" const val google_material = "1.1.0" const val google_flexbox = "2.0.1" @@ -172,7 +171,6 @@ object Deps { const val androidx_recyclerview = "androidx.recyclerview:recyclerview:${Versions.androidx_recyclerview}" const val androidx_core = "androidx.core:core:${Versions.androidx_core}" const val androidx_core_ktx = "androidx.core:core-ktx:${Versions.androidx_core}" - const val androidx_dynamic_animation = "androidx.dynamicanimation:dynamicanimation:${Versions.androidx_dynamic_animation}" const val androidx_transition = "androidx.transition:transition:${Versions.androidx_transition}" const val androidx_work_ktx = "androidx.work:work-runtime-ktx:${Versions.androidx_work}" const val androidx_work_testing = "androidx.work:work-testing:${Versions.androidx_work}" From 5f5caa4720c1f18637ba12946204e8f162da7b83 Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Tue, 18 Aug 2020 14:08:31 +0000 Subject: [PATCH 002/128] Update Android Components version to 54.0.20200818130156. --- 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 c429e7980..1560073ba 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 = "54.0.20200814130102" + const val VERSION = "54.0.20200818130156" } From cd729b39e537d89dfd7918eca6bdd394b02ba301 Mon Sep 17 00:00:00 2001 From: TejaswiKarasani Date: Tue, 18 Aug 2020 22:33:47 +0530 Subject: [PATCH 003/128] For #112,#145: Verify Search engine can be changed temporarily using Search engine (#13259) --- .../java/org/mozilla/fenix/ui/SmokeTest.kt | 66 +++++++++++++++++ .../mozilla/fenix/ui/robots/BrowserRobot.kt | 2 + .../fenix/ui/robots/NavigationToolbarRobot.kt | 6 ++ .../mozilla/fenix/ui/robots/SearchRobot.kt | 71 +++++++++++++++++++ 4 files changed, 145 insertions(+) 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 802a3a22b..7423f9050 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -16,6 +16,7 @@ import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.TestAssetHelper +import org.mozilla.fenix.ui.robots.clickUrlbar import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar @@ -254,4 +255,69 @@ class SmokeTest { } } } + + @Test + fun verifySearchEngineCanBeChangedTemporarilyUsingShortcuts() { + val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) + + homeScreen { + }.openSearch { + verifyKeyboardVisibility() + clickSearchEngineButton() + verifySearchEngineList() + changeDefaultSearchEngine("Amazon.com") + verifySearchEngineIcon("Amazon.com") + }.goToSearchEngine { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openTabDrawer { + // Changing search engine to Bing + }.openHomeScreen { + }.openSearch { + clickSearchEngineButton() + mDevice.waitForIdle() + changeDefaultSearchEngine("Bing") + verifySearchEngineIcon("Bing") + }.goToSearchEngine { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openTabDrawer { + // Changing search engine to DuckDuckGo + }.openHomeScreen { + }.openSearch { + clickSearchEngineButton() + mDevice.waitForIdle() + changeDefaultSearchEngine("DuckDuckGo") + verifySearchEngineIcon("DuckDuckGo") + }.goToSearchEngine { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openTabDrawer { + // Changing search engine to Twitter + }.openHomeScreen { + }.openSearch { + clickSearchEngineButton() + mDevice.waitForIdle() + changeDefaultSearchEngine("Twitter") + verifySearchEngineIcon("Twitter") + }.goToSearchEngine { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openTabDrawer { + // Changing search engine to Wikipedia + }.openHomeScreen { + }.openSearch { + clickSearchEngineButton() + changeDefaultSearchEngine("Wikipedia") + verifySearchEngineIcon("Wikipedia") + }.goToSearchEngine { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openTabDrawer { + // Checking whether the next search will be with default or not + }.openHomeScreen { + }.openSearch { + }.goToSearchEngine { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openNavigationToolbar { + clickUrlbar { + verifyDefaultSearchEngine("Google") + } + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt index 5d6732cce..e07d7ba8c 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt @@ -12,12 +12,14 @@ import android.net.Uri import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.pressBack import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.BundleMatchers import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt index 556007c8f..5d37179ed 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt @@ -239,6 +239,12 @@ fun navigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationTo return NavigationToolbarRobot.Transition() } +fun clickUrlbar(interact: SearchRobot.() -> Unit): SearchRobot.Transition { + urlBar().click() + SearchRobot().interact() + return SearchRobot.Transition() +} + private fun assertSuggestionsAreEqualTo(suggestionSize: Int, searchTerm: String) { mDevice.waitForIdle() awesomeBar().perform(typeText(searchTerm)) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index 8bfe0f56e..d8dc47fab 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.ui.robots +import android.widget.ToggleButton import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso.onView import androidx.test.espresso.ViewInteraction @@ -16,7 +17,9 @@ import androidx.test.espresso.action.ViewActions.typeText import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.withContentDescription +import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry @@ -28,8 +31,11 @@ import androidx.test.uiautomator.Until import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.startsWith import org.hamcrest.Matchers +import org.junit.Assert.assertEquals import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull /** @@ -47,6 +53,24 @@ class SearchRobot { fun verifySearchSettings() = assertSearchSettings() fun verifySearchBarEmpty() = assertSearchBarEmpty() + fun verifyKeyboardVisibility() = assertKeyboardVisibility(isExpectedToBeVisible = true) + fun verifySearchEngineList() = assertSearchEngineList() + fun verifySearchEngineIcon(expectedText: String) { + onView(withContentDescription(expectedText)) + } + fun verifyDefaultSearchEngine(expectedText: String) = assertDefaultSearchEngine(expectedText) + + fun changeDefaultSearchEngine(searchEngineName: String) = + selectDefaultSearchEngine(searchEngineName) + + fun clickSearchEngineButton() { + val searchEngineButton = mDevice.findObject(UiSelector() + .instance(1) + .className(ToggleButton::class.java)) + searchEngineButton.waitForExists(waitingTime) + searchEngineButton.click() + } + fun clickScanButton() { scanButton().perform(click()) } @@ -106,6 +130,11 @@ class SearchRobot { BrowserRobot().interact() return BrowserRobot.Transition() } + + fun goToSearchEngine(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition { + NavigationToolbarRobot().interact() + return NavigationToolbarRobot.Transition() + } } } @@ -178,4 +207,46 @@ fun searchScreen(interact: SearchRobot.() -> Unit): SearchRobot.Transition { return SearchRobot.Transition() } +private fun assertKeyboardVisibility(isExpectedToBeVisible: Boolean) = { + mDevice.waitNotNull( + Until.findObject( + By.text("Search Engine") + ), waitingTime + ) + assertEquals( + isExpectedToBeVisible, + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + .executeShellCommand("dumpsys input_method | grep mInputShown") + .contains("mInputShown=true") + ) +} + +private fun assertSearchEngineList() { + onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click() + onView(withText("Google")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("Amazon.com")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("Bing")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("DuckDuckGo")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("Twitter")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withText("Wikipedia")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} + +private fun selectDefaultSearchEngine(searchEngine: String) { + onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click() + onView(withText(searchEngine)) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + .perform(click()) +} + +private fun assertDefaultSearchEngine(expectedText: String) { + onView(allOf(withId(R.id.mozac_browser_toolbar_edit_icon), withContentDescription(expectedText))) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} + private fun goBackButton() = onView(allOf(withContentDescription("Navigate up"))) From d49ca515f48fad3817572d1bf235dda6de59c57e Mon Sep 17 00:00:00 2001 From: Kainalu Hagiwara Date: Fri, 14 Aug 2020 10:22:00 -0700 Subject: [PATCH 004/128] For #13330 - Remove feature flag for swipe to switch tabs. --- .../java/org/mozilla/fenix/FeatureFlags.kt | 5 -- .../fenix/browser/BaseBrowserFragment.kt | 6 +- .../mozilla/fenix/browser/BrowserFragment.kt | 22 ++--- .../res/layout/browser_gesture_wrapper.xml | 19 ----- app/src/main/res/layout/fragment_browser.xml | 85 +++++++++++-------- 5 files changed, 58 insertions(+), 79 deletions(-) delete mode 100644 app/src/main/res/layout/browser_gesture_wrapper.xml diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index da2c235cf..c3b944f2e 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -29,11 +29,6 @@ object FeatureFlags { */ val tabTray = Config.channel.isNightlyOrDebug - /** - * Enables gestures on the browser chrome that depend on a [SwipeGestureLayout] - */ - val browserChromeGestures = Config.channel.isNightlyOrDebug - /** * Enables viewing tab history */ 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 cfad14859..1acc0e059 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -168,11 +168,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session require(arguments != null) customTabSessionId = arguments?.getString(EXTRA_SESSION_ID) - val view = if (FeatureFlags.browserChromeGestures) { - inflater.inflate(R.layout.browser_gesture_wrapper, container, false) - } else { - inflater.inflate(R.layout.fragment_browser, container, false) - } + val view = inflater.inflate(R.layout.fragment_browser, container, false) val activity = activity as HomeActivity activity.themeManager.applyStatusBarTheme(activity) diff --git a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt index 9163d8ab5..797a5c34d 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -15,7 +15,6 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.google.android.material.snackbar.Snackbar -import kotlinx.android.synthetic.main.browser_gesture_wrapper.* import kotlinx.android.synthetic.main.fragment_browser.* import kotlinx.android.synthetic.main.fragment_browser.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -32,7 +31,6 @@ import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.tabs.WindowFeature import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.components.support.base.feature.ViewBoundFeatureWrapper -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.addons.runIfFragmentIsAttached import org.mozilla.fenix.components.FenixSnackbar @@ -77,19 +75,15 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler { val components = context.components return super.initializeUI(view)?.also { - // We need to wrap this whole thing in an if here because gestureLayout will not exist - // if the feature flag is off - if (FeatureFlags.browserChromeGestures) { - gestureLayout.addGestureListener( - ToolbarGestureHandler( - activity = requireActivity(), - contentLayout = browserLayout, - tabPreview = tabPreview, - toolbarLayout = browserToolbarView.view, - sessionManager = components.core.sessionManager - ) + gestureLayout.addGestureListener( + ToolbarGestureHandler( + activity = requireActivity(), + contentLayout = browserLayout, + tabPreview = tabPreview, + toolbarLayout = browserToolbarView.view, + sessionManager = components.core.sessionManager ) - } + ) val readerModeAction = BrowserToolbar.ToggleButton( diff --git a/app/src/main/res/layout/browser_gesture_wrapper.xml b/app/src/main/res/layout/browser_gesture_wrapper.xml deleted file mode 100644 index 4de55e61f..000000000 --- a/app/src/main/res/layout/browser_gesture_wrapper.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/fragment_browser.xml b/app/src/main/res/layout/fragment_browser.xml index 328f9bedd..5ed490ea6 100644 --- a/app/src/main/res/layout/fragment_browser.xml +++ b/app/src/main/res/layout/fragment_browser.xml @@ -1,53 +1,66 @@ - - - + android:layout_height="match_parent"> - + tools:context="browser.BrowserFragment"> - + + + + + + + + - + - - - + - - - + From 446f1d678eeb3024a99fce8a49023d7f5bd8c531 Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Mon, 3 Aug 2020 13:40:11 -0700 Subject: [PATCH 005/128] For #11656 - Adds addon user attributes to leanplum --- .../org/mozilla/fenix/components/metrics/MetricController.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt index 1694d89f0..6f2234948 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.components.metrics import androidx.annotation.VisibleForTesting +import com.leanplum.Leanplum import mozilla.components.browser.awesomebar.facts.BrowserAwesomeBarFacts import mozilla.components.browser.menu.facts.BrowserMenuFacts import mozilla.components.browser.toolbar.facts.ToolbarFacts @@ -193,6 +194,7 @@ internal class ReleaseMetricController( if (installedAddons is List<*>) { Addons.installedAddons.set(installedAddons.map { it.toString() }) Addons.hasInstalledAddons.set(installedAddons.size > 0) + Leanplum.setUserAttributes(mapOf("installed_addons" to installedAddons.size)) } } @@ -200,6 +202,7 @@ internal class ReleaseMetricController( if (enabledAddons is List<*>) { Addons.enabledAddons.set(enabledAddons.map { it.toString() }) Addons.hasEnabledAddons.set(enabledAddons.size > 0) + Leanplum.setUserAttributes(mapOf("enabled_addons" to enabledAddons.size)) } } From b8de7079a963efb140ed318d876f23a17a0e3d9e Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Thu, 13 Aug 2020 12:41:02 -0700 Subject: [PATCH 006/128] For #11656 - Adds docs for new leanplum attributes --- docs/mma.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/mma.md b/docs/mma.md index 4db6157ae..ab632d0f1 100644 --- a/docs/mma.md +++ b/docs/mma.md @@ -159,6 +159,16 @@ User Attributes A boolean indicating that this is a Fenix installation #8208 + + `installed_addons` + A boolean indicating that there are addons installed + #13233 + + + `enabled_addons` + A boolean indicating that there are addons enabled + #13233 + Events From 35f63f80d2292455b53b20beaecdc53b80b037dd Mon Sep 17 00:00:00 2001 From: Mozilla L10n Automation Bot Date: Wed, 19 Aug 2020 00:05:19 +0000 Subject: [PATCH 007/128] Import l10n. --- app/src/main/res/values-bs/strings.xml | 21 ++---- app/src/main/res/values-el/strings.xml | 88 ++++++++++++++++++++++++++ app/src/main/res/values-in/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 6 ++ 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml index bf619e6ae..65188be26 100644 --- a/app/src/main/res/values-bs/strings.xml +++ b/app/src/main/res/values-bs/strings.xml @@ -37,6 +37,8 @@ Označeno %1$s + + Neizabrano %1$s Izašao iz režima s više izbora @@ -164,8 +166,8 @@ Skeniraj - - Pretraživač + + Pretraživač Postavke pretraživača @@ -294,6 +296,8 @@ Postavke računa Otvori linkove u aplikacijama + + Vanjski menadžer preuzimanja Add-oni @@ -1442,9 +1446,7 @@ Prijava sa tim korisničkim imenom već postoji - - Povežite se sa Firefox računom. - + Povežite drugi uređaj Ponovo potvrdite identitet. @@ -1465,13 +1467,4 @@ OK, razumijem - - - Prečice - - Traži na - - Ovaj put, traži na: - - Prikaži prečice za pretraživanje diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 81bc9bbb3..962a21a6c 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -34,6 +34,11 @@ Επιλογή συλλογής + + Τέλος λειτουργίας πολλαπλής επιλογής + + Αποθήκευση επιλεγμένων καρτελών στη συλλογή + Το %1$s αναπτύσσεται από τη Mozilla. @@ -255,6 +260,8 @@ Εργαλεία προγραμματιστή Απομακρυσμένος εντοπισμός σφαλμάτων μέσω USB + + Εμφάνιση μηχανών αναζήτησης Εμφάνιση προτάσεων αναζήτησης @@ -271,6 +278,8 @@ Ρυθμίσεις λογαριασμού Άνοιγμα συνδέσμων σε εφαρμογές + + Εξωτερική διαχείριση λήψεων Πρόσθετα @@ -322,17 +331,25 @@ Προστασία από καταγραφή Εξαιρέσεις + + Ενεργοποίηση για όλες τις σελίδες Μάθετε περισσότερα Τηλεμετρία + + Δεδομένα χρήσης και τεχνικά δεδομένα Δεδομένα μάρκετινγκ Πειράματα + + Επιτρέπει στη Mozilla την εγκατάσταση και συλλογή δεδομένων για πειραματικές λειτουργίες + + Αναφορά καταρρεύσεων Υπηρεσία τοποθεσίας Mozilla @@ -645,6 +662,8 @@ Ανενεργό Αποδοχή ήχου και βίντεο + + Η αναπαραγωγή ήχων/βίντεο θα γίνεται σε Wi-Fi Φραγή ήχου μόνο @@ -661,6 +680,8 @@ Μενού συλλογής Συλλέξτε όλα όσα έχουν σημασία για εσάς + + Ομαδοποιήστε παρόμοιες αναζητήσεις, σελίδες και καρτέλες για γρήγορη πρόσβαση αργότερα. Επιλέξτε καρτέλες @@ -681,6 +702,12 @@ Επιλέχθηκε %d καρτέλα + + Οι καρτέλες αποθηκεύτηκαν! + + Η συλλογή αποθηκεύτηκε! + + Η καρτέλα αποθηκεύτηκε! Κλείσιμο @@ -718,8 +745,12 @@ Εκτός σύνδεσης Σύνδεση άλλης συσκευής + + Για να στείλετε μια καρτέλα, συνδεθείτε στο Firefox σε άλλη μία τουλάχιστον συσκευή. Το κατάλαβα + + Αδυναμία κοινοποίησης σε αυτή την εφαρμογή Αποστολή σε συσκευή @@ -847,17 +878,29 @@ Το Firefox Preview είναι πλέον το Firefox Nightly + + + Το Firefox Nightly ενημερώνεται κάθε βράδυ και διαθέτει νέες, πειραματικές λειτουργίες. + Ωστόσο, ενδέχεται να είναι λιγότερο σταθερό. Κάντε λήψη του beta προγράμματος περιήγησής μας για μια πιο σταθερή εμπειρία. Λήψη του Firefox για Android Beta Το Firefox Nightly έχει μετακινηθεί + + + Αυτή η εφαρμογή δεν θα λαμβάνει πλέον ενημερώσεις ασφαλείας. Σταματήστε τη χρήση αυτής της εφαρμογής και μεταβείτε στο νέο Nightly. + \n\nΓια να μεταφέρετε τους σελιδοδείκτες, τις συνδέσεις και το ιστορικό σας σε άλλη εφαρμογή, δημιουργήστε ένα λογαριασμό Firefox. Εναλλαγή στο νέο Nightly Το Firefox Nightly έχει μετακινηθεί + + + Αυτή η εφαρμογή δεν θα λαμβάνει πλέον ενημερώσεις ασφαλείας. Αποκτήστε το νέο Nightly και σταματήστε τη χρήση αυτής της εφαρμογής. + \n\nΓια να μεταφέρετε τους σελιδοδείκτες, τις συνδέσεις και το ιστορικό σας σε άλλη εφαρμογή, δημιουργήστε ένα λογαριασμό Firefox. Αποκτήστε το νέο Nightly @@ -872,6 +915,11 @@ Γνωρίστε το %s Δείτε τι νέο υπάρχει + + Έχετε ερωτήσεις σχετικά με το επανασχεδιασμένο %s; Θέλετε να μάθετε τι έχει αλλάξει; + + Λάβετε απαντήσεις εδώ Αξιοποιήστε στο έπακρο το %s. @@ -888,6 +936,9 @@ Αυτόματο απόρρητο + + Οι ρυθμίσεις απορρήτου και ασφάλειας αποκλείουν ιχνηλάτες, κακόβουλο λογισμικό και εταιρείες που σας ακολουθούν. Τυπική (προεπιλογή) @@ -900,6 +951,8 @@ Άνοιγμα ρυθμίσεων Το απόρρητό σας + + Διαβάστε τη σημείωση απορρήτου μας Κλείσιμο @@ -918,6 +971,10 @@ Φωτεινό θέμα + + Οι καρτέλες απεστάλησαν! + + Η καρτέλα απεστάλη! Δεν ήταν δυνατή η αποστολή @@ -933,11 +990,18 @@ Χρήση email + + Το Firefox θα σταματήσει να συγχρονίζεται με το λογαριασμό σας, αλλά δεν θα διαγράψει τα δεδομένα περιήγησης από αυτή τη συσκευή. + + Το %s θα σταματήσει να συγχρονίζεται με το λογαριασμό σας, αλλά δεν θα διαγράψει τα δεδομένα περιήγησης από αυτή τη συσκευή. Αποσύνδεση Ακύρωση + + Δεν είναι δυνατή η επεξεργασία προεπιλεγμένων φακέλων + Ρυθμίσεις προστασίας @@ -951,12 +1015,22 @@ Μάθετε περισσότερα Τυπική (προεπιλογή) + + Φραγή λιγότερων ιχνηλατών. Οι σελίδες θα φορτώνονται κανονικά. + + Τι αποκλείει η τυπική προστασία από καταγραφή Αυστηρή + + Φραγή περισσότερων ιχνηλατών, διαφημίσεων και αναδυόμενων παραθύρων. Οι σελίδες φορτώνονται ταχύτερα, αλλά ορισμένα μέρη ενδέχεται να μην λειτουργούν. + + Τι αποκλείει η αυστηρή προστασία από καταγραφή Προσαρμοσμένη Επιλέξτε ιχνηλάτες και σενάρια για αποκλεισμό. + + Τι αποκλείει η προσαρμοσμένη προστασία από καταγραφή Cookies @@ -980,6 +1054,9 @@ Cryptominers Fingerprinters + Αποκλείεται + + Επιτρέπεται Ιχνηλάτες κοινωνικών δικτύων @@ -990,6 +1067,15 @@ Fingerprinters Περιεχόμενο καταγραφής + + Η προστασία είναι ΕΝΕΡΓΗ για αυτή τη σελίδα + + Η προστασία είναι ΑΝΕΝΕΡΓΗ για αυτή τη σελίδα + + Η ενισχυμένη προστασία από καταγραφή είναι ανενεργή για αυτή τη σελίδα + + Πλοήγηση προς τα πίσω Τα δικαιώματά σας @@ -1088,6 +1174,8 @@ Όνομα χρήστη Κωδικός πρόσβασης + + Εισάγετε ξανά το PIN σας Αυτή η σύνδεση δεν είναι ασφαλής. Οι λογαριασμοί που εισάγονται εδώ ενδέχεται να παραβιαστούν. diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index b12c2a8e5..b77ebff5f 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -1402,7 +1402,7 @@ %s dihapus - Selamat datang ke %s yang benar-benar baru + Selamat datang di %s terbaru Sebuah peramban yang telah didesain ulang sepenuhnya, dengan peningkatan kinerja dan fitur untuk membantu anda dalam melakukan sesuatu secara daring.\n\nHarap tunggu selama kami memperbarui %s dengan milik anda diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 573324abf..76d43f528 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -36,12 +36,18 @@ Naam Collectie selecteren + + Multiselectiemodus verlaten Geselecteerde tabbladen in collectie opslaan %1$s geselecteerd Selectie %1$s ongedaan gemaakt + + Multiselectiemodus verlaten + + Multiselectiemodus geactiveerd, selecteer tabbladen om in een collectie op te slaan Geselecteerd From 0b2e6297748245c482c989895a5f3fff593edf0f Mon Sep 17 00:00:00 2001 From: Oana Horvath Date: Wed, 19 Aug 2020 18:06:40 +0300 Subject: [PATCH 008/128] Closes #13219: Changes device long-tap delay before UI tests (#13502) --- .../fenix/helpers/HomeActivityTestRule.kt | 27 ++++++++++++++++--- .../org/mozilla/fenix/ui/SettingsAboutTest.kt | 3 +-- .../ui/robots/SettingsSubMenuAboutRobot.kt | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt index 9beaf4524..2b47a32a0 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt @@ -5,7 +5,9 @@ package org.mozilla.fenix.helpers import androidx.test.espresso.intent.rule.IntentsTestRule +import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.ActivityTestRule +import androidx.test.uiautomator.UiDevice import org.mozilla.fenix.HomeActivity /** @@ -16,7 +18,12 @@ import org.mozilla.fenix.HomeActivity */ class HomeActivityTestRule(initialTouchMode: Boolean = false, launchActivity: Boolean = true) : - ActivityTestRule(HomeActivity::class.java, initialTouchMode, launchActivity) + ActivityTestRule(HomeActivity::class.java, initialTouchMode, launchActivity) { + override fun beforeActivityLaunched() { + super.beforeActivityLaunched() + setLongTapTimeout() + } +} /** * A [org.junit.Rule] to handle shared test set up for tests on [HomeActivity]. This adds @@ -26,5 +33,19 @@ class HomeActivityTestRule(initialTouchMode: Boolean = false, launchActivity: Bo * @param launchActivity See [IntentsTestRule] */ -class HomeActivityIntentTestRule(initialTouchMode: Boolean = false, launchActivity: Boolean = true) : - IntentsTestRule(HomeActivity::class.java, initialTouchMode, launchActivity) +class HomeActivityIntentTestRule( + initialTouchMode: Boolean = false, + launchActivity: Boolean = true +) : + IntentsTestRule(HomeActivity::class.java, initialTouchMode, launchActivity) { + override fun beforeActivityLaunched() { + super.beforeActivityLaunched() + setLongTapTimeout() + } +} + +// changing the device preference for Touch and Hold delay, to avoid long-clicks instead of a single-click +fun setLongTapTimeout() { + val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + mDevice.executeShellCommand("settings put secure long_press_timeout 3000") +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt index b9963cb98..26368bd0a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt @@ -10,7 +10,6 @@ import okhttp3.mockwebserver.MockWebServer import org.junit.Rule import org.junit.Before import org.junit.After -import org.junit.Ignore import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityIntentTestRule @@ -69,7 +68,7 @@ class SettingsAboutTest { } } - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/13219") + @Test fun verifyAboutFirefoxPreview() { homeScreen { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt index 4e6a9e3ef..54ae398c4 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuAboutRobot.kt @@ -222,7 +222,7 @@ private fun assertLibrariesUsed() { .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .perform(click()) - onView(withId(R.id.action_bar)).check(matches(hasDescendant(withText(containsString("Firefox Preview | OSS Libraries"))))) + onView(withId(R.id.toolbar)).check(matches(hasDescendant(withText(containsString("Firefox Preview | OSS Libraries"))))) Espresso.pressBack() } From 929ec541b0ede182fe07db630a4b41e1a0b79271 Mon Sep 17 00:00:00 2001 From: MarcLeclair Date: Wed, 19 Aug 2020 12:04:49 -0400 Subject: [PATCH 009/128] 13899 fix formatting issue (#13900) 13899 re worded the performance readme and removed the reference to debuggable builds 13899 fixed some nits --- README.md | 26 +-- docs/metrics.md | 486 ++++++++++++++++++++++++------------------------ 2 files changed, 257 insertions(+), 255 deletions(-) diff --git a/README.md b/README.md index b93808d9a..ef1d872d0 100644 --- a/README.md +++ b/README.md @@ -105,21 +105,23 @@ you want these variants to be: #### Performance Build Variants For accurate performance measurements, read this section! -If you want to analyze performance during **local development** (note: there is a non-trivial performance impact - see caveats): -- Recommendation: use a debuggable variant (see "local.properties helpers" below) with local Leanplum, Adjust, & Sentry API tokens: contact the front-end perf group for access to them -- Rationale: There are numerous performance-impacting differences between debug and release variants so we need a release variant. To profile, we also need debuggable, which is disabled by default for release variants. If API tokens are not provided, the SDKs may change their behavior in non-trivial ways. -- Caveats: - - debuggable has a non-trivial & variable impact on performance but is needed to take profiles. - - Random experiment opt-in & feature flags may impact performance (see [perf-frontend-issues#45](https://github.com/mozilla-mobile/perf-frontend-issues/issues/45) for mitigation). - - This is slower to build than debug builds because it does additional tasks (e.g. minification) similar to other release builds +To analyze performance during **local development** build a production variant locally (this could either be the Nightly, beta or release). Otherwise, you could also grab a pre-existing APK if you don't need to test some local changes. Then, use the Firefox profiler to profile what you need! -If you want to run **performance tests/benchmarks** in automation or locally: -- Recommendation: production builds. If debuggable is required, use recommendation above but note the caveat above. If your needs are not met, please contact the front-end perf group to identify a new solution. -- Rationale: like the rationale above, we need release variants so the choice is based on the debuggable flag. +For more information on how to use the profiler or how to use the build, refer to this [how to measure performance with the build](https://wiki.mozilla.org/Performance/How_to_get_started_on_Fenix) -For additional context on these recommendations, see [the perf build variant analysis](https://docs.google.com/document/d/1aW-m0HYncTDDiRz_2x6EjcYkjBpL9SHhhYix13Vil30/edit#). +If you want to run **performance tests/benchmarks** in automation or locally use a production build since it is much closer in behavior compared to what users see in the wild. -Before you can install any release variants, **you will need to sign them:** see [Automatically signing release builds](#automatically-sign-release-builds) for details. +Before you can install any release builds, **You will need to sign production build variants:** see [Automatically signing release builds](#automatically-sign-release-builds) for details. + +##### Known disabled-by-default features +Some features are disabled by default when Fenix is built locally. This can be problematic at times for checking performance since you might want to know how your code behaves with those features. +The known features that are disabled by default are: +- Sentry +- Leanplum +- Adjust +- Mozilla Location Services (also known as MLS) +- Firebase Push Services +- Telemetry (only disabled by default in debug builds) ## Pre-push hooks To reduce review turn-around time, we'd like all pushes to run tests locally. We'd diff --git a/docs/metrics.md b/docs/metrics.md index fdf276a7a..88633ba61 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -35,8 +35,8 @@ The following metrics are added to the ping: | Name | Type | Description | Data reviews | Extras | Expiration | [Data Sensitivity](https://wiki.mozilla.org/Firefox/Data_Collection) | | --- | --- | --- | --- | --- | --- | --- | -| activation.activation_id |[uuid](https://mozilla.github.io/glean/book/user/metrics/uuid.html) |An alternate identifier, not correlated with the client_id, generated once and only sent with the activation ping. |[1](https://github.com/mozilla-mobile/fenix/pull/1707#issuecomment-486972209)||2020-10-01 | | -| activation.identifier |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A hashed and salted version of the Google Advertising ID from the device. This will never be sent in a ping that also contains the client_id. |[1](https://github.com/mozilla-mobile/fenix/pull/1707#issuecomment-486972209)||2020-10-01 | | +| activation.activation_id |[uuid](https://mozilla.github.io/glean/book/user/metrics/uuid.html) |An alternate identifier, not correlated with the client_id, generated once and only sent with the activation ping. |[1](https://github.com/mozilla-mobile/fenix/pull/1707#issuecomment-486972209)||2020-10-01 |4 | +| activation.identifier |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A hashed and salted version of the Google Advertising ID from the device. This will never be sent in a ping that also contains the client_id. |[1](https://github.com/mozilla-mobile/fenix/pull/1707#issuecomment-486972209)||2020-10-01 |4 | ## events @@ -48,185 +48,185 @@ The following metrics are added to the ping: | Name | Type | Description | Data reviews | Extras | Expiration | [Data Sensitivity](https://wiki.mozilla.org/Firefox/Data_Collection) | | --- | --- | --- | --- | --- | --- | --- | -| about_page.libraries_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Libraries that we use" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 | | -| about_page.licensing_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Licensing information" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 | | -| 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 |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 | | -| about_page.rights_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Know your rights" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 | | -| about_page.support_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Support" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 | | -| 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 |[1](https://github.com/mozilla-mobile/fenix/pull/8318)|
  • addon_id: The id of the add-on that was interacted with in the toolbar menu
|2020-10-01 | | -| addons.open_addons_in_settings |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user accessed "Add-ons" from the Settings |[1](https://github.com/mozilla-mobile/fenix/pull/8318)||2020-10-01 | | -| app_theme.dark_theme_selected |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user selected Dark Theme |[1](https://github.com/mozilla-mobile/fenix/pull/7968)|
  • source: The source from where dark theme was selected. The source can be 'SETTINGS' or 'ONBOARDING'
|2020-10-01 | | -| autoplay.setting_changed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user changed their autoplay setting to either block_cellular, block_audio, or block_all. |[1](https://github.com/mozilla-mobile/fenix/pull/13041#issuecomment-665777411)|
  • autoplay_setting: The new setting for autoplay: block_cellular, block_audio, or block_all.
|2021-02-01 | | -| autoplay.visited_setting |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user visited the autoplay settings screen |[1](https://github.com/mozilla-mobile/fenix/pull/13041#issuecomment-665777411)||2021-02-01 | | -| bookmarks_management.copied |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user copied a bookmark. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.edited |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user edited the title and/or URL of an existing bookmark. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.folder_add |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user added a new bookmark folder. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.folder_remove |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed a bookmark folder. |[1](https://github.com/mozilla-mobile/fenix/pull/3724)||2020-10-01 | | -| bookmarks_management.moved |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user moved an existing bookmark or folder to another folder. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.multi_removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed multiple bookmarks at once. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.open_in_new_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a bookmark in a new tab. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.open_in_new_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened multiple bookmarks at once in new tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.open_in_private_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a bookmark in a new private tab. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.open_in_private_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened multiple bookmarks at once in new private tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed a bookmark item. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| bookmarks_management.shared |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user shared a bookmark. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 | | -| collections.add_tab_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the "add tab" button in the three dot menu of collections |[1](https://github.com/mozilla-mobile/fenix/pull/4358)||2020-10-01 | | -| collections.all_tabs_restored |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "open tabs" from collection menu |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.long_press |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user long pressed on a tab, triggering the collection creation screen |[1](https://github.com/mozilla-mobile/fenix/pull/4358)||2020-10-01 | | -| collections.removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped delete collection from collection menu |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.rename_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "rename collection" button in the three dot menu |[1](https://github.com/mozilla-mobile/fenix/pull/4539)||2020-10-01 | | -| collections.renamed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user renamed a collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.save_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "save to collection" button on either the home or browser screen, triggering the collection creation screen to open (tab_select_opened) |[1](https://github.com/mozilla-mobile/fenix/pull/4358)|
  • from_screen: A string representing the screen from which the user pressed the save button. Currently one of: `browserMenu`, `homeMenu` or `home`
|2020-10-01 | | -| collections.saved |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user saved a list of tabs to a new collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)|
  • tabs_open: The number of tabs open in the current session
  • tabs_selected: The number of tabs added to the collection
|2020-10-01 | | -| collections.shared |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped share collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.tab_removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped remove tab from collection tab list |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.tab_restored |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user restored a tab from collection tab list |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.tab_select_opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the select tabs screen (the first step of the collection creation flow) |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 | | -| collections.tabs_added |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user saved a list of tabs to an existing collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)|
  • tabs_open: The number of tabs open in the current session
  • tabs_selected: The number of tabs added to the collection
|2020-10-01 | | -| context_menu.item_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped an item in the browsers context menu |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)|
  • named: The name of the item that was tapped. Available items are: ``` open_in_new_tab, open_in_private_tab, open_image_in_new_tab, save_image, share_link, copy_link, copy_image_location ```
|2020-10-01 | | -| contextual_hint.tracking_protection.dismiss |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The enhanced tracking protection contextual hint was dismissed by pressing the close button |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 | | -| contextual_hint.tracking_protection.display |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The enhanced tracking protection contextual hint was displayed. |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 | | -| contextual_hint.tracking_protection.inside_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user tapped inside of the etp contextual hint (which brings up the etp panel for this site). |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 | | -| contextual_hint.tracking_protection.outside_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user tapped outside of the etp contextual hint (which has no effect). |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 | | -| crash_reporter.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The crash reporter was closed |[1](https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708)|
  • crash_submitted: A boolean that tells us whether or not the user submitted a crash report
|2020-10-01 | | -| crash_reporter.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The crash reporter was displayed |[1](https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708)||2020-10-01 | | -| custom_tab.action_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the action button provided by the launching app |[1](https://github.com/mozilla-mobile/fenix/pull/1697)||2020-10-01 | | -| custom_tab.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the custom tab |[1](https://github.com/mozilla-mobile/fenix/pull/1697)||2020-10-01 | | -| custom_tab.menu |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the custom tabs menu |[1](https://github.com/mozilla-mobile/fenix/pull/1697)||2020-10-01 | | -| download_notification.cancel |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user cancelled a download in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| download_notification.in_app_open |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a downloaded file in the in-app notification link |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| download_notification.in_app_try_again |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on try again when a download fails in the in-app notification link |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| download_notification.open |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a downloaded file in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| download_notification.pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user paused a download in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| download_notification.resume |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user resumed a download in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| download_notification.try_again |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on try again when a download fails in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 | | -| error_page.visited_error |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user encountered an error page |[1](https://github.com/mozilla-mobile/fenix/pull/2491#issuecomment-492414486)|
  • error_type: The error type of the error page encountered
|2020-10-01 | | -| events.app_opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the app (from cold start, to the homescreen or browser) |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)|
  • source: The method used to open Fenix. Possible values are: `app_icon`, `custom_tab` or `link`
|2020-10-01 | | -| events.app_opened_all_startup |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the app to the HomeActivity. The HomeActivity encompasses the home screen, browser screen, settings screen, collections and other screens in the nav_graph. This differs from the app_opened probe because it measures all startups, not just cold startup. Note: There is a short gap between the time application goes into background and the time android reports the application going into the background. Note: This metric does not cover the following cases: Case # 1 -> a). open a link(for example, gmail) with in-app Browser (metric report custom_tab startup) b). press home button c). open gmail again (which brings us back to in app browser). Step c will not report startup metric. Case # 2 -> a). open fenix b). press home button c). launch fenix through app switcher/recent apps. step c will not report startup type. |[1](https://github.com/mozilla-mobile/fenix/pull/12114#pullrequestreview-445245341)|
  • source: The method used to open Fenix. Possible values are `app_icon`, `custom_tab`, `link` or `unknown`
|2020-12-01 | | +| about_page.libraries_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Libraries that we use" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 |2 | +| about_page.licensing_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Licensing information" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 |2 | +| 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 |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-01 |2 | +| about_page.rights_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on "Know your rights" item from About page |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-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 |[1](https://github.com/mozilla-mobile/fenix/pull/8047)||2020-10-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 |[1](https://github.com/mozilla-mobile/fenix/pull/8318)|
  • addon_id: The id of the add-on that was interacted with in the toolbar menu
|2020-10-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 |[1](https://github.com/mozilla-mobile/fenix/pull/8318)||2020-10-01 |2 | +| app_theme.dark_theme_selected |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user selected Dark Theme |[1](https://github.com/mozilla-mobile/fenix/pull/7968)|
  • source: The source from where dark theme was selected. The source can be 'SETTINGS' or 'ONBOARDING'
|2020-10-01 |2 | +| autoplay.setting_changed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user changed their autoplay setting to either block_cellular, block_audio, or block_all. |[1](https://github.com/mozilla-mobile/fenix/pull/13041#issuecomment-665777411)|
  • autoplay_setting: The new setting for autoplay: block_cellular, block_audio, or block_all.
|2021-02-01 |2 | +| autoplay.visited_setting |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user visited the autoplay settings screen |[1](https://github.com/mozilla-mobile/fenix/pull/13041#issuecomment-665777411)||2021-02-01 |2 | +| bookmarks_management.copied |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user copied a bookmark. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.edited |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user edited the title and/or URL of an existing bookmark. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.folder_add |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user added a new bookmark folder. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.folder_remove |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed a bookmark folder. |[1](https://github.com/mozilla-mobile/fenix/pull/3724)||2020-10-01 |2 | +| bookmarks_management.moved |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user moved an existing bookmark or folder to another folder. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.multi_removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed multiple bookmarks at once. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.open_in_new_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a bookmark in a new tab. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.open_in_new_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened multiple bookmarks at once in new tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.open_in_private_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a bookmark in a new private tab. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.open_in_private_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened multiple bookmarks at once in new private tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed a bookmark item. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| bookmarks_management.shared |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user shared a bookmark. |[1](https://github.com/mozilla-mobile/fenix/pull/1708)||2020-10-01 |2 | +| collections.add_tab_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the "add tab" button in the three dot menu of collections |[1](https://github.com/mozilla-mobile/fenix/pull/4358)||2020-10-01 |2 | +| collections.all_tabs_restored |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "open tabs" from collection menu |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.long_press |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user long pressed on a tab, triggering the collection creation screen |[1](https://github.com/mozilla-mobile/fenix/pull/4358)||2020-10-01 |2 | +| collections.removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped delete collection from collection menu |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.rename_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "rename collection" button in the three dot menu |[1](https://github.com/mozilla-mobile/fenix/pull/4539)||2020-10-01 |2 | +| collections.renamed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user renamed a collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.save_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "save to collection" button on either the home or browser screen, triggering the collection creation screen to open (tab_select_opened) |[1](https://github.com/mozilla-mobile/fenix/pull/4358)|
  • from_screen: A string representing the screen from which the user pressed the save button. Currently one of: `browserMenu`, `homeMenu` or `home`
|2020-10-01 |2 | +| collections.saved |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user saved a list of tabs to a new collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)|
  • tabs_open: The number of tabs open in the current session
  • tabs_selected: The number of tabs added to the collection
|2020-10-01 |1, 2 | +| collections.shared |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped share collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.tab_removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped remove tab from collection tab list |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.tab_restored |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user restored a tab from collection tab list |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.tab_select_opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the select tabs screen (the first step of the collection creation flow) |[1](https://github.com/mozilla-mobile/fenix/pull/3935)||2020-10-01 |1, 2 | +| collections.tabs_added |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user saved a list of tabs to an existing collection |[1](https://github.com/mozilla-mobile/fenix/pull/3935)|
  • tabs_open: The number of tabs open in the current session
  • tabs_selected: The number of tabs added to the collection
|2020-10-01 |1, 2 | +| context_menu.item_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped an item in the browsers context menu |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)|
  • named: The name of the item that was tapped. Available items are: ``` open_in_new_tab, open_in_private_tab, open_image_in_new_tab, save_image, share_link, copy_link, copy_image_location ```
|2020-10-01 |2 | +| contextual_hint.tracking_protection.dismiss |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The enhanced tracking protection contextual hint was dismissed by pressing the close button |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 |2 | +| contextual_hint.tracking_protection.display |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The enhanced tracking protection contextual hint was displayed. |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 |2 | +| contextual_hint.tracking_protection.inside_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user tapped inside of the etp contextual hint (which brings up the etp panel for this site). |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 |2 | +| contextual_hint.tracking_protection.outside_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user tapped outside of the etp contextual hint (which has no effect). |[1](https://github.com/mozilla-mobile/fenix/pull/11923)||2020-10-01 |2 | +| crash_reporter.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The crash reporter was closed |[1](https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708)|
  • crash_submitted: A boolean that tells us whether or not the user submitted a crash report
|2020-10-01 |2 | +| crash_reporter.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The crash reporter was displayed |[1](https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708)||2020-10-01 |2 | +| custom_tab.action_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the action button provided by the launching app |[1](https://github.com/mozilla-mobile/fenix/pull/1697)||2020-10-01 |2 | +| custom_tab.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the custom tab |[1](https://github.com/mozilla-mobile/fenix/pull/1697)||2020-10-01 |2 | +| custom_tab.menu |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the custom tabs menu |[1](https://github.com/mozilla-mobile/fenix/pull/1697)||2020-10-01 |2 | +| download_notification.cancel |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user cancelled a download in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| download_notification.in_app_open |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a downloaded file in the in-app notification link |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| download_notification.in_app_try_again |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on try again when a download fails in the in-app notification link |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| download_notification.open |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a downloaded file in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| download_notification.pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user paused a download in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| download_notification.resume |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user resumed a download in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| download_notification.try_again |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped on try again when a download fails in the download notification |[1](https://github.com/mozilla-mobile/fenix/pull/6554)||2020-10-01 |2 | +| error_page.visited_error |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user encountered an error page |[1](https://github.com/mozilla-mobile/fenix/pull/2491#issuecomment-492414486)|
  • error_type: The error type of the error page encountered
|2020-10-01 |2 | +| events.app_opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the app (from cold start, to the homescreen or browser) |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)|
  • source: The method used to open Fenix. Possible values are: `app_icon`, `custom_tab` or `link`
|2020-10-01 |2 | +| events.app_opened_all_startup |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the app to the HomeActivity. The HomeActivity encompasses the home screen, browser screen, settings screen, collections and other screens in the nav_graph. This differs from the app_opened probe because it measures all startups, not just cold startup. Note: There is a short gap between the time application goes into background and the time android reports the application going into the background. Note: This metric does not cover the following cases: Case # 1 -> a). open a link(for example, gmail) with in-app Browser (metric report custom_tab startup) b). press home button c). open gmail again (which brings us back to in app browser). Step c will not report startup metric. Case # 2 -> a). open fenix b). press home button c). launch fenix through app switcher/recent apps. step c will not report startup type. |[1](https://github.com/mozilla-mobile/fenix/pull/12114#pullrequestreview-445245341)|
  • source: The method used to open Fenix. Possible values are `app_icon`, `custom_tab`, `link` or `unknown`
|2020-12-01 |2 | | events.app_received_intent |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The system received an Intent for the HomeActivity. An intent is received an external entity wants to the app to display content. Intents can be received when the app is closed – at which point the app will be opened – or when the app is already opened – at which point the already open app will make changes such as loading a url. This can be used loosely as a heuristic for when the user requested to open the app. The HomeActivity encompasses the home screen and browser screen but may include other screens. This differs from the app_opened probe because it measures all startups, not just cold startup. |[1](https://github.com/mozilla-mobile/fenix/pull/11940/)|
  • source: The method used to open Fenix. Possible values are `app_icon`, `custom_tab`, `link` or `unknown`
|2020-12-01 | | -| events.browser_menu_action |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A browser menu item was tapped |[1](https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708), [2](https://github.com/mozilla-mobile/fenix/pull/5098#issuecomment-529658996), [3](https://github.com/mozilla-mobile/fenix/pull/6310)|
  • item: A string containing the name of the item the user tapped. These items include: Settings, Help, Desktop Site toggle on/off, Find in Page, New Tab, Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button, Quit, Reader Mode On, Reader Mode Off, Open In app, Add To Top Sites, Add-ons Manager, Bookmarks, History
|2020-10-01 | | -| events.entered_url |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user entered a url |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)|
  • autocomplete: A boolean that tells us whether the URL was autofilled by an Autocomplete suggestion
|2020-10-01 | | -| events.opened_link |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a link with Fenix |[1](https://github.com/mozilla-mobile/fenix/pull/5975)|
  • mode: The mode the link was opened in. Either 'PRIVATE' or 'NORMAL'.
|2020-10-01 | | -| events.performed_search |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user performed a search |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673), [2](https://github.com/mozilla-mobile/fenix/pull/1677)|
  • source: A string that tells us how the user performed the search. Possible values are: * default.action * default.suggestion * shortcut.action * shortcut.suggestion
|2020-10-01 | | -| events.preference_toggled |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user toggled a boolean preference in settings |[1](https://github.com/mozilla-mobile/fenix/pull/1896), [2](https://github.com/mozilla-mobile/fenix/pull/5704), [3](https://github.com/mozilla-mobile/fenix/pull/5886), [4](https://github.com/mozilla-mobile/fenix/pull/5975), [5](https://github.com/mozilla-mobile/fenix/pull/6352), [6](https://github.com/mozilla-mobile/fenix/pull/6601), [7](https://github.com/mozilla-mobile/fenix/pull/6746)|
  • enabled: Whether or not the preference is *now* enabled
  • preference_key: The preference key for the boolean (true/false) preference the user toggled. We currently track: show_search_suggestions, remote_debugging, telemetry, tracking_protection, search_bookmarks, search_browsing_history, show_clipboard_suggestions, show_search_shortcuts, open_links_in_a_private_tab (bug in implementation https://github.com/mozilla-mobile/fenix/issues/7384), pref_key_sync_logins, pref_key_sync_bookmarks, pref_key_sync_history, pref_key_show_voice_search, and pref_key_show_search_suggestions_in_private.
|2020-10-01 | | -| events.search_bar_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the search bar |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)|
  • source: The view the user was on when they initiated the search (For example: `Home` or `Browser`)
|2020-10-01 | | -| events.tab_counter_menu_action |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A tab counter menu item was tapped |[1](https://github.com/mozilla-mobile/fenix/pull/11533)|
  • item: A string containing the name of the item the user tapped. These items are: New tab, New private tab, Close tab
|2020-10-01 | | -| events.whats_new_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the "what's new" page button |[1](https://github.com/mozilla-mobile/fenix/pull/5090)||2020-10-01 | | -| find_in_page.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the find in page UI |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)||2020-10-01 | | -| find_in_page.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the find in page UI |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)||2020-10-01 | | -| find_in_page.searched_page |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user searched the page |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)||2020-10-01 | | -| history.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the history screen |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 | | -| history.opened_item |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a history item |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 | | -| history.removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed a history item |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 | | -| history.removed_all |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed all history items |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 | | -| history.shared |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user shared a history item |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 | | -| login_dialog.cancelled |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt was cancelled |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 | | -| login_dialog.displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt was displayed |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 | | -| login_dialog.never_save |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt "never save" button was pressed |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 | | -| login_dialog.saved |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt "save" button was pressed |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 | | -| logins.copy_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user copied a piece of a login in saved logins |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 | | -| logins.delete_saved_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user confirms delete of a saved login |[1](https://github.com/mozilla-mobile/fenix/issues/11208)||2020-10-01 | | -| logins.open_individual_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user accessed an individual login in saved logins |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 | | -| logins.open_login_editor |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user entered the edit screen for an individual saved login |[1](https://github.com/mozilla-mobile/fenix/issues/11208)||2020-10-01 | | -| logins.open_logins |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user accessed Logins in Settings |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 | | -| logins.save_edited_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user saves changes made to an individual login |[1](https://github.com/mozilla-mobile/fenix/issues/11208)||2020-10-01 | | -| logins.save_logins_setting_changed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user changed their setting for asking to save logins |[1](https://github.com/mozilla-mobile/fenix/pull/7767)|
  • setting: The new setting for saving logins the user selected. Either `ask_to_save` or `never_save`
|2020-10-01 | | -| logins.view_password_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user viewed a password in an individual saved login |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 | | -| media_notification.pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the pause icon on the media notification |[1](https://github.com/mozilla-mobile/fenix/pull/5520)||2020-10-01 | | -| media_notification.play |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the play icon on the media notification |[1](https://github.com/mozilla-mobile/fenix/pull/5520)||2020-10-01 | | -| media_state.pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Media playback was paused. |[1](https://github.com/mozilla-mobile/fenix/pull/6463)||2020-10-01 | | -| media_state.play |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Media started playing. |[1](https://github.com/mozilla-mobile/fenix/pull/6463)||2020-10-01 | | -| media_state.stop |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Media playback has ended. |[1](https://github.com/mozilla-mobile/fenix/pull/6463)||2020-10-01 | | -| onboarding.finish |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user taps starts browsing and ends the onboarding experience. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 | | -| onboarding.fxa_auto_signin |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding automatic sign in card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 | | -| onboarding.fxa_manual_signin |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding manual sign in card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 | | -| onboarding.pref_toggled_private_browsing |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The private browsing preference was selected from the onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 | | -| onboarding.pref_toggled_theme_picker |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The device theme was chosen using the theme picker onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)|
  • theme: A string that indicates the theme LIGHT, DARK, or FOLLOW DEVICE. Default: FOLLOW DEVICE
|2020-10-01 | | -| onboarding.pref_toggled_toolbar_position |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The toolbar position preference was chosen from the onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)|
  • position: A string that indicates the position of the toolbar TOP or BOTTOM. Default: BOTTOM
|2020-10-01 | | -| onboarding.pref_toggled_tracking_prot |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tracking protection preference was chosen from the onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)|
  • setting: A string that indicates the Tracking Protection policy STANDARD or STRICT. Default: Toggle ON, STANDARD
|2020-10-01 | | -| onboarding.privacy_notice |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding privacy notice card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 | | -| onboarding.whats_new |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding What\'s New card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 | | -| pocket.pocket_top_site_clicked |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user clicked on the trending Pocket top site |[1](https://github.com/mozilla-mobile/fenix/pull/8098)||2020-10-01 | | -| pocket.pocket_top_site_removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed the trending Pocket top site |[1](https://github.com/mozilla-mobile/fenix/pull/8098)||2020-10-01 | | -| private_browsing_mode.garbage_icon |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the garbage can icon on the private browsing home page, deleting all private tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 | | -| private_browsing_mode.notification_delete |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the private browsing mode notification's "Delete and Open" button. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 | | -| private_browsing_mode.notification_open |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the private browsing mode notification's "Open" button. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 | | -| private_browsing_mode.notification_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the private browsing mode notification itself. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 | | -| private_browsing_mode.snackbar_undo |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "undo" button in the snackbar that is shown when the garbage icon is tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 | | -| private_browsing_shortcut.cfr_add_shortcut |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "Add shortcut" button when the contextual feature recommender appeared. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 | | -| private_browsing_shortcut.cfr_cancel |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "No thanks" button when the contextual feature recommender appeared. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 | | -| private_browsing_shortcut.create_shortcut |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "Add private browsing shortcut" button in settings. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 | | -| private_browsing_shortcut.pinned_shortcut_priv |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the pinned private shortcut in Android home screen, opening up a new private search. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 | | -| private_browsing_shortcut.static_shortcut_priv |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the long-press shortcut "Open new private tab", opening up a new private search. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 | | -| private_browsing_shortcut.static_shortcut_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the long-press shortcut "Open new tab", opening up a new search. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 | | -| progressive_web_app.background |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user puts the PWA into the background. |[1](https://github.com/mozilla-mobile/fenix/pull/11859)|
  • time_ms: The current time in ms when the PWA was backgrounded.
|2021-03-01 | | -| progressive_web_app.foreground |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user brings the PWA into the foreground. |[1](https://github.com/mozilla-mobile/fenix/pull/11859)|
  • time_ms: The current time in ms when the PWA was brought to the foreground.
|2021-03-01 | | -| progressive_web_app.homescreen_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user taps on PWA homescreen icon |[1](https://github.com/mozilla-mobile/fenix/pull/11859)||2021-03-01 | | -| progressive_web_app.install_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user installs a PWA. Could be a shortcut or added to homescreen. |[1](https://github.com/mozilla-mobile/fenix/pull/11859)||2021-03-01 | | -| qr_scanner.navigation_allowed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "allow" on the prompt, directing the user to the website scanned |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 | | -| qr_scanner.navigation_denied |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "deny" on the prompt, putting the user back to the scanning view |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 | | -| qr_scanner.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the QR scanner |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 | | -| qr_scanner.prompt_displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user scanned a QR code, causing a confirmation prompt to display asking if they want to navigate to the page |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 | | -| reader_mode.appearance |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the appearance button |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-10-01 | | -| reader_mode.available |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Reader mode is available for the current page |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-10-01 | | -| reader_mode.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed reader mode |[1](https://github.com/mozilla-mobile/fenix/pull/4328)||2020-10-01 | | -| reader_mode.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened reader mode |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-10-01 | | +| events.browser_menu_action |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A browser menu item was tapped |[1](https://github.com/mozilla-mobile/fenix/pull/1214#issue-264756708), [2](https://github.com/mozilla-mobile/fenix/pull/5098#issuecomment-529658996), [3](https://github.com/mozilla-mobile/fenix/pull/6310)|
  • item: A string containing the name of the item the user tapped. These items include: Settings, Help, Desktop Site toggle on/off, Find in Page, New Tab, Private Tab, Share, Report Site Issue, Back/Forward button, Reload Button, Quit, Reader Mode On, Reader Mode Off, Open In app, Add To Top Sites, Add-ons Manager, Bookmarks, History
|2020-10-01 |2 | +| events.entered_url |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user entered a url |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)|
  • autocomplete: A boolean that tells us whether the URL was autofilled by an Autocomplete suggestion
|2020-10-01 |2 | +| events.opened_link |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a link with Fenix |[1](https://github.com/mozilla-mobile/fenix/pull/5975)|
  • mode: The mode the link was opened in. Either 'PRIVATE' or 'NORMAL'.
|2020-10-01 |2 | +| events.performed_search |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user performed a search |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673), [2](https://github.com/mozilla-mobile/fenix/pull/1677)|
  • source: A string that tells us how the user performed the search. Possible values are: * default.action * default.suggestion * shortcut.action * shortcut.suggestion
|2020-10-01 |2 | +| events.preference_toggled |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user toggled a boolean preference in settings |[1](https://github.com/mozilla-mobile/fenix/pull/1896), [2](https://github.com/mozilla-mobile/fenix/pull/5704), [3](https://github.com/mozilla-mobile/fenix/pull/5886), [4](https://github.com/mozilla-mobile/fenix/pull/5975), [5](https://github.com/mozilla-mobile/fenix/pull/6352), [6](https://github.com/mozilla-mobile/fenix/pull/6601), [7](https://github.com/mozilla-mobile/fenix/pull/6746)|
  • enabled: Whether or not the preference is *now* enabled
  • preference_key: The preference key for the boolean (true/false) preference the user toggled. We currently track: show_search_suggestions, remote_debugging, telemetry, tracking_protection, search_bookmarks, search_browsing_history, show_clipboard_suggestions, show_search_shortcuts, open_links_in_a_private_tab (bug in implementation https://github.com/mozilla-mobile/fenix/issues/7384), pref_key_sync_logins, pref_key_sync_bookmarks, pref_key_sync_history, pref_key_show_voice_search, and pref_key_show_search_suggestions_in_private.
|2020-10-01 |1, 2 | +| events.search_bar_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the search bar |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)|
  • source: The view the user was on when they initiated the search (For example: `Home` or `Browser`)
|2020-10-01 |2 | +| events.tab_counter_menu_action |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A tab counter menu item was tapped |[1](https://github.com/mozilla-mobile/fenix/pull/11533)|
  • item: A string containing the name of the item the user tapped. These items are: New tab, New private tab, Close tab
|2020-10-01 |2 | +| events.whats_new_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the "what's new" page button |[1](https://github.com/mozilla-mobile/fenix/pull/5090)||2020-10-01 |2 | +| find_in_page.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the find in page UI |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)||2020-10-01 |2 | +| find_in_page.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the find in page UI |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)||2020-10-01 |2 | +| find_in_page.searched_page |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user searched the page |[1](https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010)||2020-10-01 |2 | +| history.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the history screen |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 |2 | +| history.opened_item |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a history item |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 |2 | +| history.removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed a history item |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 |2 | +| history.removed_all |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed all history items |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 |2 | +| history.shared |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user shared a history item |[1](https://github.com/mozilla-mobile/fenix/pull/3940)||2020-10-01 |2 | +| login_dialog.cancelled |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt was cancelled |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 |2 | +| login_dialog.displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt was displayed |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 |2 | +| login_dialog.never_save |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt "never save" button was pressed |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 |2 | +| login_dialog.saved |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The login dialog prompt "save" button was pressed |[1](https://github.com/mozilla-mobile/fenix/pull/13050)||2021-02-01 |2 | +| logins.copy_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user copied a piece of a login in saved logins |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 |2 | +| logins.delete_saved_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user confirms delete of a saved login |[1](https://github.com/mozilla-mobile/fenix/issues/11208)||2020-10-01 |2 | +| logins.open_individual_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user accessed an individual login in saved logins |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 |2 | +| logins.open_login_editor |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user entered the edit screen for an individual saved login |[1](https://github.com/mozilla-mobile/fenix/issues/11208)||2020-10-01 |2 | +| logins.open_logins |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user accessed Logins in Settings |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 |2 | +| logins.save_edited_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user saves changes made to an individual login |[1](https://github.com/mozilla-mobile/fenix/issues/11208)||2020-10-01 |2 | +| logins.save_logins_setting_changed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user changed their setting for asking to save logins |[1](https://github.com/mozilla-mobile/fenix/pull/7767)|
  • setting: The new setting for saving logins the user selected. Either `ask_to_save` or `never_save`
|2020-10-01 |2 | +| logins.view_password_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user viewed a password in an individual saved login |[1](https://github.com/mozilla-mobile/fenix/pull/6352)||2020-10-01 |2 | +| media_notification.pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the pause icon on the media notification |[1](https://github.com/mozilla-mobile/fenix/pull/5520)||2020-10-01 |2 | +| media_notification.play |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the play icon on the media notification |[1](https://github.com/mozilla-mobile/fenix/pull/5520)||2020-10-01 |2 | +| media_state.pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Media playback was paused. |[1](https://github.com/mozilla-mobile/fenix/pull/6463)||2020-10-01 |2 | +| media_state.play |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Media started playing. |[1](https://github.com/mozilla-mobile/fenix/pull/6463)||2020-10-01 |2 | +| media_state.stop |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Media playback has ended. |[1](https://github.com/mozilla-mobile/fenix/pull/6463)||2020-10-01 |2 | +| onboarding.finish |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user taps starts browsing and ends the onboarding experience. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 |2 | +| onboarding.fxa_auto_signin |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding automatic sign in card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 |2 | +| onboarding.fxa_manual_signin |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding manual sign in card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 |2 | +| onboarding.pref_toggled_private_browsing |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The private browsing preference was selected from the onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 |2 | +| onboarding.pref_toggled_theme_picker |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The device theme was chosen using the theme picker onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)|
  • theme: A string that indicates the theme LIGHT, DARK, or FOLLOW DEVICE. Default: FOLLOW DEVICE
|2020-10-01 |2 | +| onboarding.pref_toggled_toolbar_position |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The toolbar position preference was chosen from the onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)|
  • position: A string that indicates the position of the toolbar TOP or BOTTOM. Default: BOTTOM
|2020-10-01 |2 | +| onboarding.pref_toggled_tracking_prot |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tracking protection preference was chosen from the onboarding card. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)|
  • setting: A string that indicates the Tracking Protection policy STANDARD or STRICT. Default: Toggle ON, STANDARD
|2020-10-01 |2 | +| onboarding.privacy_notice |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding privacy notice card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 |2 | +| onboarding.whats_new |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The onboarding What\'s New card was tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/11867)||2020-10-01 |2 | +| pocket.pocket_top_site_clicked |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user clicked on the trending Pocket top site |[1](https://github.com/mozilla-mobile/fenix/pull/8098)||2020-10-01 |2 | +| pocket.pocket_top_site_removed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removed the trending Pocket top site |[1](https://github.com/mozilla-mobile/fenix/pull/8098)||2020-10-01 |2 | +| private_browsing_mode.garbage_icon |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the garbage can icon on the private browsing home page, deleting all private tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 |2 | +| private_browsing_mode.notification_delete |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the private browsing mode notification's "Delete and Open" button. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 |2 | +| private_browsing_mode.notification_open |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the private browsing mode notification's "Open" button. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 |2 | +| private_browsing_mode.notification_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the private browsing mode notification itself. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 |2 | +| private_browsing_mode.snackbar_undo |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "undo" button in the snackbar that is shown when the garbage icon is tapped. |[1](https://github.com/mozilla-mobile/fenix/pull/4968)||2020-10-01 |2 | +| private_browsing_shortcut.cfr_add_shortcut |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "Add shortcut" button when the contextual feature recommender appeared. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 |2 | +| private_browsing_shortcut.cfr_cancel |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "No thanks" button when the contextual feature recommender appeared. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 |2 | +| private_browsing_shortcut.create_shortcut |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "Add private browsing shortcut" button in settings. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 |2 | +| private_browsing_shortcut.pinned_shortcut_priv |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the pinned private shortcut in Android home screen, opening up a new private search. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 |2 | +| private_browsing_shortcut.static_shortcut_priv |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the long-press shortcut "Open new private tab", opening up a new private search. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 |2 | +| private_browsing_shortcut.static_shortcut_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the long-press shortcut "Open new tab", opening up a new search. |[1](https://github.com/mozilla-mobile/fenix/pull/5194)||2020-10-01 |2 | +| progressive_web_app.background |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user puts the PWA into the background. |[1](https://github.com/mozilla-mobile/fenix/pull/11859)|
  • time_ms: The current time in ms when the PWA was backgrounded.
|2021-03-01 |2 | +| progressive_web_app.foreground |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user brings the PWA into the foreground. |[1](https://github.com/mozilla-mobile/fenix/pull/11859)|
  • time_ms: The current time in ms when the PWA was brought to the foreground.
|2021-03-01 |2 | +| progressive_web_app.homescreen_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user taps on PWA homescreen icon |[1](https://github.com/mozilla-mobile/fenix/pull/11859)||2021-03-01 |2 | +| progressive_web_app.install_tap |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user installs a PWA. Could be a shortcut or added to homescreen. |[1](https://github.com/mozilla-mobile/fenix/pull/11859)||2021-03-01 |2 | +| qr_scanner.navigation_allowed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "allow" on the prompt, directing the user to the website scanned |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 |2 | +| qr_scanner.navigation_denied |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "deny" on the prompt, putting the user back to the scanning view |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 |2 | +| qr_scanner.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the QR scanner |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 |2 | +| qr_scanner.prompt_displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user scanned a QR code, causing a confirmation prompt to display asking if they want to navigate to the page |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-10-01 |2 | +| reader_mode.appearance |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the appearance button |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-10-01 |2 | +| reader_mode.available |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Reader mode is available for the current page |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-10-01 |2 | +| reader_mode.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed reader mode |[1](https://github.com/mozilla-mobile/fenix/pull/4328)||2020-10-01 |2 | +| reader_mode.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened reader mode |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-10-01 |2 | | search_shortcuts.selected |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user selected a search shortcut engine to use |[1](https://github.com/mozilla-mobile/fenix/pull/1202#issuecomment-476870449)|
  • engine: The name of the built-in search engine the user selected as a string
|2020-10-01 | | -| search_suggestions.enable_in_private |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user enabled receiving search suggestions in private sessions |[1](https://github.com/mozilla-mobile/fenix/pull/6746)||2020-10-01 | | -| search_widget.new_tab_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed anywhere from the Firefox logo until the start of the microphone icon, opening a new tab search screen. |[1](https://github.com/mozilla-mobile/fenix/pull/4714)||2020-10-01 | | -| search_widget.voice_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the microphone icon, opening a new voice search screen. |[1](https://github.com/mozilla-mobile/fenix/pull/4714)||2020-10-01 | | -| search_widget_cfr.add_widget_pressed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user pressed the "add widget" button. |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 | | -| search_widget_cfr.canceled |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user dismissed the search widget cfr by tapping outside of the prompt |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 | | -| search_widget_cfr.displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The search widget cfr was displayed. |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 | | -| search_widget_cfr.not_now_pressed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user pressed the "not now" button. |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 | | -| sync_account.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the sync account page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_account.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the sync account page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_account.send_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user sent the current tab to another FxA device |[1](https://github.com/mozilla-mobile/fenix/pull/5106)||2020-10-01 | | -| sync_account.sign_in_to_send_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "sign in to send tab" button inside the share tab menu |[1](https://github.com/mozilla-mobile/fenix/pull/5106)||2020-10-01 | | -| sync_account.sync_now |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the sync now button on the sync account page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_auth.auto_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User signed into FxA via an account shared from another locally installed Mozilla application (e.g. Fennec) |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 | | -| sync_auth.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the sync page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_auth.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the sync authentication page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_auth.other_external |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User authenticated via FxA using an unknown mechanism. "Known" mechanisms are currently sign-in, sign-up and pairing |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 | | -| sync_auth.paired |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User signed into FxA by pairing with a different Firefox browser, using a QR code |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 | | -| sync_auth.recovered |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Account manager automatically recovered FxA authentication state without direct user involvement |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 | | -| sync_auth.scan_pairing |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the scan pairing button on the sync authentication page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_auth.sign_in |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the sign in button on the sync authentication page and was successfully signed in to FxA |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_auth.sign_out |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the sign out button on the sync account page and was successfully signed out of FxA |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 | | -| sync_auth.sign_up |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User registered a new Firefox Account, and was signed into it |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 | | -| sync_auth.use_email |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user chose to use their email to sign in instead of scanning a QR code, counterpart to "scan_pairing" |[1](https://github.com/mozilla-mobile/fenix/pull/9835#pullrequestreview-398641844)||2020-10-01 | | -| sync_auth.use_email_problem |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user chose to use their email to sign in after an account problem |[1](https://github.com/mozilla-mobile/fenix/pull/9835#pullrequestreview-398641844)||2020-10-01 | | -| tab.media_pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the pause icon on a tab from the home screen |[1](https://github.com/mozilla-mobile/fenix/pull/5266)||2020-10-01 | | -| tab.media_play |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the play icon on a tab from the home screen |[1](https://github.com/mozilla-mobile/fenix/pull/5266)||2020-10-01 | | -| tabs_tray.close_all_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the close all tabs button in the three dot menu within the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.closed_existing_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed an existing tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.menu_opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened three three dot menu in the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.new_private_tab_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a new private tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.new_tab_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a new tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.normal_mode_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user switched to normal mode |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.opened_existing_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened an existing tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.private_mode_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user switched to private mode |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.save_to_collection |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the save to collection button in the three dot menu within the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tabs_tray.share_all_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the share all tabs button in the three dot menu within the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 | | -| tip.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tip was closed |[1](https://github.com/mozilla-mobile/fenix/pull/9836)|
  • identifier: The identifier of the tip closed
|2020-10-01 | | -| tip.displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tip was displayed |[1](https://github.com/mozilla-mobile/fenix/pull/9836)|
  • identifier: The identifier of the tip displayed
|2020-10-01 | | -| tip.pressed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tip's button was pressed |[1](https://github.com/mozilla-mobile/fenix/pull/9836)|
  • identifier: The identifier of the tip the action was taken on
|2020-10-01 | | -| toolbar_settings.changed_position |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user selected a new position for the toolbar |[1](https://github.com/mozilla-mobile/fenix/pull/6608)|
  • position: A string that indicates the new position of the toolbar TOP or BOTTOM
|2020-10-01 | | -| top_sites.open_default |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a default top site |[1](https://github.com/mozilla-mobile/fenix/pull/10752)||2020-10-01 | | -| top_sites.open_in_new_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opens a new tab based on a top site item |[1](https://github.com/mozilla-mobile/fenix/pull/7523)||2020-10-01 | | -| top_sites.open_in_private_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opens a new private tab based on a top site item |[1](https://github.com/mozilla-mobile/fenix/pull/7523)||2020-10-01 | | -| top_sites.remove |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removes a top site item |[1](https://github.com/mozilla-mobile/fenix/pull/7523)||2020-10-01 | | -| tracking_protection.etp_setting_changed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user changed their tracking protection level setting to either strict, standard, or custom. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188), [2](https://github.com/mozilla-mobile/fenix/pull/11383)|
  • etp_setting: The new setting for ETP: strict, standard, custom
|2020-10-01 | | -| tracking_protection.etp_settings |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened tracking protection settings through settings. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 | | -| tracking_protection.etp_shield |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the tracking protection shield icon in toolbar. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 | | -| tracking_protection.etp_tracker_list |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed into a list of categorized trackers in tracking protection panel. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 | | -| tracking_protection.exception_added |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user added a tracking protection exception through the TP toggle in the panel. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 | | -| tracking_protection.panel_settings |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened tracking protection settings from the panel. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 | | -| user_specified_search_engines.custom_engine_added |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user added a new custom search engine |[1](https://github.com/mozilla-mobile/fenix/pull/6918)||2020-10-01 | | -| user_specified_search_engines.custom_engine_deleted |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user deleted a custom search engine |[1](https://github.com/mozilla-mobile/fenix/pull/6918)||2020-10-01 | | -| voice_search.tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user selected the voice search button on the search screen. |[1](https://github.com/mozilla-mobile/fenix/pull/10785)||2020-10-01 | | +| search_suggestions.enable_in_private |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user enabled receiving search suggestions in private sessions |[1](https://github.com/mozilla-mobile/fenix/pull/6746)||2020-10-01 |1, 2 | +| search_widget.new_tab_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed anywhere from the Firefox logo until the start of the microphone icon, opening a new tab search screen. |[1](https://github.com/mozilla-mobile/fenix/pull/4714)||2020-10-01 |2 | +| search_widget.voice_button |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the microphone icon, opening a new voice search screen. |[1](https://github.com/mozilla-mobile/fenix/pull/4714)||2020-10-01 |2 | +| search_widget_cfr.add_widget_pressed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user pressed the "add widget" button. |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 |2 | +| search_widget_cfr.canceled |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user dismissed the search widget cfr by tapping outside of the prompt |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 |2 | +| search_widget_cfr.displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The search widget cfr was displayed. |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 |2 | +| search_widget_cfr.not_now_pressed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user pressed the "not now" button. |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 |2 | +| sync_account.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the sync account page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_account.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the sync account page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_account.send_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user sent the current tab to another FxA device |[1](https://github.com/mozilla-mobile/fenix/pull/5106)||2020-10-01 |2 | +| sync_account.sign_in_to_send_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the "sign in to send tab" button inside the share tab menu |[1](https://github.com/mozilla-mobile/fenix/pull/5106)||2020-10-01 |2 | +| sync_account.sync_now |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the sync now button on the sync account page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_auth.auto_login |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User signed into FxA via an account shared from another locally installed Mozilla application (e.g. Fennec) |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 |1, 2 | +| sync_auth.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the sync page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_auth.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the sync authentication page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_auth.other_external |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User authenticated via FxA using an unknown mechanism. "Known" mechanisms are currently sign-in, sign-up and pairing |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 |1, 2 | +| sync_auth.paired |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User signed into FxA by pairing with a different Firefox browser, using a QR code |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 |1, 2 | +| sync_auth.recovered |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Account manager automatically recovered FxA authentication state without direct user involvement |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 |1, 2 | +| sync_auth.scan_pairing |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the scan pairing button on the sync authentication page |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_auth.sign_in |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the sign in button on the sync authentication page and was successfully signed in to FxA |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_auth.sign_out |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the sign out button on the sync account page and was successfully signed out of FxA |[1](https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532)||2020-10-01 |2 | +| sync_auth.sign_up |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |User registered a new Firefox Account, and was signed into it |[1](https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300)||2020-10-01 |1, 2 | +| sync_auth.use_email |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user chose to use their email to sign in instead of scanning a QR code, counterpart to "scan_pairing" |[1](https://github.com/mozilla-mobile/fenix/pull/9835#pullrequestreview-398641844)||2020-10-01 |2 | +| sync_auth.use_email_problem |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user chose to use their email to sign in after an account problem |[1](https://github.com/mozilla-mobile/fenix/pull/9835#pullrequestreview-398641844)||2020-10-01 |2 | +| tab.media_pause |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the pause icon on a tab from the home screen |[1](https://github.com/mozilla-mobile/fenix/pull/5266)||2020-10-01 |2 | +| tab.media_play |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the play icon on a tab from the home screen |[1](https://github.com/mozilla-mobile/fenix/pull/5266)||2020-10-01 |2 | +| tabs_tray.close_all_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the close all tabs button in the three dot menu within the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.closed_existing_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed an existing tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.menu_opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened three three dot menu in the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.new_private_tab_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a new private tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.new_tab_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a new tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.normal_mode_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user switched to normal mode |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.opened_existing_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened an existing tab |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.private_mode_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user switched to private mode |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.save_to_collection |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the save to collection button in the three dot menu within the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tabs_tray.share_all_tabs |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the share all tabs button in the three dot menu within the tabs tray |[1](https://github.com/mozilla-mobile/fenix/pull/12036)||2020-10-01 |2 | +| tip.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tip was closed |[1](https://github.com/mozilla-mobile/fenix/pull/9836)|
  • identifier: The identifier of the tip closed
|2020-10-01 |2 | +| tip.displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tip was displayed |[1](https://github.com/mozilla-mobile/fenix/pull/9836)|
  • identifier: The identifier of the tip displayed
|2020-10-01 |2 | +| tip.pressed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The tip's button was pressed |[1](https://github.com/mozilla-mobile/fenix/pull/9836)|
  • identifier: The identifier of the tip the action was taken on
|2020-10-01 |2 | +| toolbar_settings.changed_position |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |The user selected a new position for the toolbar |[1](https://github.com/mozilla-mobile/fenix/pull/6608)|
  • position: A string that indicates the new position of the toolbar TOP or BOTTOM
|2020-10-01 |2 | +| top_sites.open_default |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened a default top site |[1](https://github.com/mozilla-mobile/fenix/pull/10752)||2020-10-01 |2 | +| top_sites.open_in_new_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opens a new tab based on a top site item |[1](https://github.com/mozilla-mobile/fenix/pull/7523)||2020-10-01 |2 | +| top_sites.open_in_private_tab |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opens a new private tab based on a top site item |[1](https://github.com/mozilla-mobile/fenix/pull/7523)||2020-10-01 |2 | +| top_sites.remove |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user removes a top site item |[1](https://github.com/mozilla-mobile/fenix/pull/7523)||2020-10-01 |2 | +| tracking_protection.etp_setting_changed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user changed their tracking protection level setting to either strict, standard, or custom. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188), [2](https://github.com/mozilla-mobile/fenix/pull/11383)|
  • etp_setting: The new setting for ETP: strict, standard, custom
|2020-10-01 |2 | +| tracking_protection.etp_settings |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened tracking protection settings through settings. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 |2 | +| tracking_protection.etp_shield |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed the tracking protection shield icon in toolbar. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 |2 | +| tracking_protection.etp_tracker_list |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user pressed into a list of categorized trackers in tracking protection panel. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 |2 | +| tracking_protection.exception_added |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user added a tracking protection exception through the TP toggle in the panel. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 |2 | +| tracking_protection.panel_settings |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened tracking protection settings from the panel. |[1](https://github.com/mozilla-mobile/fenix/pull/5414#issuecomment-532847188)||2020-10-01 |2 | +| user_specified_search_engines.custom_engine_added |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user added a new custom search engine |[1](https://github.com/mozilla-mobile/fenix/pull/6918)||2020-10-01 |2 | +| user_specified_search_engines.custom_engine_deleted |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user deleted a custom search engine |[1](https://github.com/mozilla-mobile/fenix/pull/6918)||2020-10-01 |2 | +| voice_search.tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user selected the voice search button on the search screen. |[1](https://github.com/mozilla-mobile/fenix/pull/10785)||2020-10-01 |2 | ## first-session @@ -248,11 +248,11 @@ The following metrics are added to the ping: | Name | Type | Description | Data reviews | Extras | Expiration | [Data Sensitivity](https://wiki.mozilla.org/Firefox/Data_Collection) | | --- | --- | --- | --- | --- | --- | --- | -| first_session.adgroup |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the AdGroup that was used to source this installation. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586480836)||2020-10-01 | | -| first_session.campaign |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the campaign that is responsible for this installation. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 | | -| first_session.creative |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The identifier of the creative material that the user interacted with. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 | | -| first_session.network |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the Network that sourced this installation. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 | | -| first_session.timestamp |[datetime](https://mozilla.github.io/glean/book/user/metrics/datetime.html) |The Glean generated date and time of the installation. This is unique per app install, though the rest of the data in this ping is from Adjust and will remain static across installs. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 | | +| first_session.adgroup |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the AdGroup that was used to source this installation. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586480836)||2020-10-01 |1, 2 | +| first_session.campaign |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the campaign that is responsible for this installation. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 |1, 2 | +| first_session.creative |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The identifier of the creative material that the user interacted with. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 |1, 2 | +| first_session.network |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the Network that sourced this installation. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 |1, 2 | +| first_session.timestamp |[datetime](https://mozilla.github.io/glean/book/user/metrics/datetime.html) |The Glean generated date and time of the installation. This is unique per app install, though the rest of the data in this ping is from Adjust and will remain static across installs. |[1](https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202)||2020-10-01 |1, 2 | ## metrics @@ -264,61 +264,61 @@ The following metrics are added to the ping: | Name | Type | Description | Data reviews | Extras | Expiration | [Data Sensitivity](https://wiki.mozilla.org/Firefox/Data_Collection) | | --- | --- | --- | --- | --- | --- | --- | -| addons.enabled_addons |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |A list of all enabled add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/11080)||2020-10-01 | | -| addons.has_enabled_addons |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the user has enabled add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/8318)||2020-10-01 | | -| addons.has_installed_addons |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the user has installed add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/8318)||2020-10-01 | | -| addons.installed_addons |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |A list of all installed add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/11080)||2020-10-01 | | -| browser.search.ad_clicks |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |Records clicks of adverts on SERP pages. The key format is ‘’. |[1](https://github.com/mozilla-mobile/fenix/pull/10112)||2020-10-01 | | -| browser.search.in_content |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |Records the type of interaction a user has on SERP pages. |[1](https://github.com/mozilla-mobile/fenix/pull/10167)||2020-10-01 | | -| browser.search.with_ads |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |Records counts of SERP pages with adverts displayed. The key format is ‘’. |[1](https://github.com/mozilla-mobile/fenix/pull/10112)||2020-10-01 | | -| events.total_uri_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter of URIs visited by the user in the current session, including page reloads. This does not include background page requests and URIs from embedded pages or private browsing but may be incremented without user interaction by website scripts that programmatically redirect to a new location. |[1](https://github.com/mozilla-mobile/fenix/pull/1785), [2](https://github.com/mozilla-mobile/fenix/pull/8314)||2020-10-01 | | -| metrics.adjust_ad_group |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust ad group ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/9253)||2020-10-01 | | -| metrics.adjust_campaign |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust campaign ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/5579)||2020-10-01 | | -| metrics.adjust_creative |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust creative ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/9253)||2020-10-01 | | -| metrics.adjust_network |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust network ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/9253)||2020-10-01 | | -| metrics.default_browser |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Is Fenix the default browser? |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)||2020-10-01 | | -| metrics.default_moz_browser |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the default browser on device if and only if it's a Mozilla owned product |[1](https://github.com/mozilla-mobile/fenix/pull/1953/), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 | | -| metrics.has_open_tabs |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |A boolean that indicates if the user has any open NORMAL tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/12024)||2020-10-01 | | -| metrics.has_recent_pwas |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |A boolean that indicates if the user has recently used PWAs. See recently_used_pwa_count for the actual count. |[1](https://github.com/mozilla-mobile/fenix/pull/11982#pullrequestreview-437963817)||2020-12-01 | | -| metrics.has_top_sites |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |A boolean that indicates if the user has top sites |[1](https://github.com/mozilla-mobile/fenix/pull/9556)||2020-10-01 | | -| metrics.mozilla_products |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |A list of all the Mozilla products installed on device. We currently scan for: Firefox, Firefox Beta, Firefox Aurora, Firefox Nightly, Firefox Fdroid, Firefox Lite, Reference Browser, Reference Browser Debug, Fenix, Focus, and Lockwise. |[1](https://github.com/mozilla-mobile/fenix/pull/1953/), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 | | -| metrics.recently_used_pwa_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many PWAs a user has recently used. Threshold for "recency" set in HomeActivity#PWA_RECENTLY_USED_THRESHOLD. Currently we are not told by the OS when a PWA is removed by the user, so we use the "recently used" heuristic to judge how many PWAs are still active, as a proxy for "installed". This value will only be set if the user has at least *one* recently used PWA. If they have 0, this metric will not be sent, resulting in a null value during analysis on the server-side. To disambiguate between a failed `recently_used_pwa_count` metric and 0 recent PWAs, please see `has_recent_pwas`. |[1](https://github.com/mozilla-mobile/fenix/pull/11982#pullrequestreview-437963817)||2020-12-01 | | -| metrics.search_count |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |The labels for this counter are `.`. If the search engine is bundled with Fenix `search-engine-name` will be the name of the search engine. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be `custom`. `source` will be: `action`, `suggestion`, `widget` or `shortcut` (depending on the source from which the search started). Also added the `other` option for the source but it should never enter on this case. |[1](https://github.com/mozilla-mobile/fenix/pull/1677), [2](https://github.com/mozilla-mobile/fenix/pull/5216), [3](https://github.com/mozilla-mobile/fenix/pull/7310)||2020-10-01 | | -| metrics.search_widget_installed |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the search widget is installed |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 | | -| metrics.tabs_open_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many NORMAL tabs a user has open. This value will only be set if the user has at least *one* open tab. If they have 0, this ping will not get sent, resulting in a null value. To disambiguate between a failed `tabs_open_count` ping and 0 open tabs, please see `has_open_tabs`. |[1](https://github.com/mozilla-mobile/fenix/pull/12024)||2020-10-01 | | -| metrics.toolbar_position |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string that indicates the new position of the toolbar TOP or BOTTOM |[1](https://github.com/mozilla-mobile/fenix/pull/6608)||2020-10-01 | | -| metrics.top_sites_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many top sites a user has. This value will only be set if the user has at least *one* top site. If they have 0, this ping will not get sent, resulting in a null value. To disambiguate between a failed `top_sites_count` ping and 0 top sites, please see `has_top_sites`. |[1](https://github.com/mozilla-mobile/fenix/pull/9556)||2020-10-01 | | -| perf.awesomebar.bookmark_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a bookmarks awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| perf.awesomebar.clipboard_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a clipboard awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| perf.awesomebar.history_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a history awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| perf.awesomebar.search_engine_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a search engine awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| perf.awesomebar.session_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a session awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| perf.awesomebar.shortcuts_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a shortcuts awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| perf.awesomebar.synced_tabs_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a synced tabs awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 | | -| preferences.accessibility_services |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has touch exploration or switch services enabled. These are built into the Android OS, not Fenix prefs. default: "" |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.open_links_in_a_private_tab |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled open links in a private tab. default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.open_links_in_app |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has the open links in apps feature enabled. default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11446)||2020-10-01 | | -| preferences.remote_debugging |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has remote debugging enabled default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.search_bookmarks |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled bookmark search suggestions default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.search_browsing_history |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled browsing history suggestions. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.search_suggestions_private |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled showing search suggestions in private mode. default: false (we prompt the user, asking them to make a selection) |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.show_clipboard_suggestions |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled clipboard search suggestions. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.show_search_shortcuts |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled search shortcuts. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.show_search_suggestions |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has search suggestions enabled default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.show_voice_search |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled the voice search button. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.sync |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user is signed into FxA default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.sync_items |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |The list of items the user has chosen to sync with FxA. default: "" if the user is signed out. Otherwise defaults to whatever is set in their FxA account. New accounts set: [bookmarks, history, passwords, tabs] |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.telemetry |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has telemetry enabled. Note we should never receive a "false" value for this since telemetry would not send in that case. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.theme |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |The theme the user has enabled. "light," "dark," "system," or "battery" default: "system" for API 28+, else "light" |[1](https://github.com/mozilla-mobile/fenix/pull/11446)||2020-10-01 | | -| preferences.toolbar_position |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |The position of the toolbar default: bottom (defaults to top if the user has accessibility services) |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| preferences.tracking_protection |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |What type of enhanced tracking protection the user has enabled. "standard," "strict," "custom," or "" (if disabled) default: "standard" |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 | | -| search.default_engine.code |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |If the search engine is pre-loaded with Fenix this value will be the search engine identifier. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be "custom" |[1](https://github.com/mozilla-mobile/fenix/pull/1606), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 | | -| search.default_engine.name |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |If the search engine is pre-loaded with Fenix this value will be the search engine name. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be "custom" |[1](https://github.com/mozilla-mobile/fenix/pull/1606), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 | | -| search.default_engine.submission_url |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |If the search engine is pre-loaded with Fenix this value will be he base URL we use to build the search query for the search engine. For example: https://mysearchengine.com/?query=%s. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be "custom" |[1](https://github.com/mozilla-mobile/fenix/pull/1606), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 | | -| storage.stats.app_bytes |[memory_distribution](https://mozilla.github.io/glean/book/user/metrics/memory_distribution.html) |The size of the app's APK and related files as installed: this is expected to be larger than download size. This is the output of [StorageStats.getAppBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getAppBytes()) so see that for details. This value is only available on Android 8+. A similar value may be available on the Google Play dashboard: we can use this value to see if that value is reliable enough. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 | | -| storage.stats.cache_bytes |[memory_distribution](https://mozilla.github.io/glean/book/user/metrics/memory_distribution.html) |The size of all cached data in the app. This is the output of [StorageStats.getCacheBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getCacheBytes()) so see that for details. This value is only available on Android 8+. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 | | -| storage.stats.data_dir_bytes |[memory_distribution](https://mozilla.github.io/glean/book/user/metrics/memory_distribution.html) |The size of all data minus `cache_bytes`. This is the output of [StorageStats.getDataBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getDataBytes()) except we subtract the value of `cache_bytes` so the cache is not measured redundantly; see that method for details. This value is only available on Android 8+. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 | | -| storage.stats.query_stats_duration |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |How long it took to query the device for the StorageStats that contain the file size information. The docs say it may be expensive so we want to ensure it's not too expensive. This value is only available on Android 8+. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 | | +| addons.enabled_addons |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |A list of all enabled add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/11080)||2020-10-01 |2 | +| addons.has_enabled_addons |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the user has enabled add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/8318)||2020-10-01 |2 | +| addons.has_installed_addons |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the user has installed add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/8318)||2020-10-01 |2 | +| addons.installed_addons |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |A list of all installed add-ons on the device. |[1](https://github.com/mozilla-mobile/fenix/pull/11080)||2020-10-01 |2 | +| browser.search.ad_clicks |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |Records clicks of adverts on SERP pages. The key format is ‘’. |[1](https://github.com/mozilla-mobile/fenix/pull/10112)||2020-10-01 |2 | +| browser.search.in_content |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |Records the type of interaction a user has on SERP pages. |[1](https://github.com/mozilla-mobile/fenix/pull/10167)||2020-10-01 |2 | +| browser.search.with_ads |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |Records counts of SERP pages with adverts displayed. The key format is ‘’. |[1](https://github.com/mozilla-mobile/fenix/pull/10112)||2020-10-01 |2 | +| events.total_uri_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter of URIs visited by the user in the current session, including page reloads. This does not include background page requests and URIs from embedded pages or private browsing but may be incremented without user interaction by website scripts that programmatically redirect to a new location. |[1](https://github.com/mozilla-mobile/fenix/pull/1785), [2](https://github.com/mozilla-mobile/fenix/pull/8314)||2020-10-01 |2 | +| metrics.adjust_ad_group |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust ad group ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/9253)||2020-10-01 |2 | +| metrics.adjust_campaign |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust campaign ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/5579)||2020-10-01 |1 | +| metrics.adjust_creative |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust creative ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/9253)||2020-10-01 |2 | +| metrics.adjust_network |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string containing the Adjust network ID from which the user installed Fenix. This will not send on the first session the user runs. If the install is organic, this will be empty. |[1](https://github.com/mozilla-mobile/fenix/pull/9253)||2020-10-01 |2 | +| metrics.default_browser |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Is Fenix the default browser? |[1](https://github.com/mozilla-mobile/fenix/pull/1067#issuecomment-474598673)||2020-10-01 |2 | +| metrics.default_moz_browser |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |The name of the default browser on device if and only if it's a Mozilla owned product |[1](https://github.com/mozilla-mobile/fenix/pull/1953/), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 |1, 2 | +| metrics.has_open_tabs |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |A boolean that indicates if the user has any open NORMAL tabs. |[1](https://github.com/mozilla-mobile/fenix/pull/12024)||2020-10-01 |2 | +| metrics.has_recent_pwas |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |A boolean that indicates if the user has recently used PWAs. See recently_used_pwa_count for the actual count. |[1](https://github.com/mozilla-mobile/fenix/pull/11982#pullrequestreview-437963817)||2020-12-01 |2 | +| metrics.has_top_sites |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |A boolean that indicates if the user has top sites |[1](https://github.com/mozilla-mobile/fenix/pull/9556)||2020-10-01 |2 | +| metrics.mozilla_products |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |A list of all the Mozilla products installed on device. We currently scan for: Firefox, Firefox Beta, Firefox Aurora, Firefox Nightly, Firefox Fdroid, Firefox Lite, Reference Browser, Reference Browser Debug, Fenix, Focus, and Lockwise. |[1](https://github.com/mozilla-mobile/fenix/pull/1953/), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 |1, 2 | +| metrics.recently_used_pwa_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many PWAs a user has recently used. Threshold for "recency" set in HomeActivity#PWA_RECENTLY_USED_THRESHOLD. Currently we are not told by the OS when a PWA is removed by the user, so we use the "recently used" heuristic to judge how many PWAs are still active, as a proxy for "installed". This value will only be set if the user has at least *one* recently used PWA. If they have 0, this metric will not be sent, resulting in a null value during analysis on the server-side. To disambiguate between a failed `recently_used_pwa_count` metric and 0 recent PWAs, please see `has_recent_pwas`. |[1](https://github.com/mozilla-mobile/fenix/pull/11982#pullrequestreview-437963817)||2020-12-01 |2 | +| metrics.search_count |[labeled_counter](https://mozilla.github.io/glean/book/user/metrics/labeled_counters.html) |The labels for this counter are `.`. If the search engine is bundled with Fenix `search-engine-name` will be the name of the search engine. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be `custom`. `source` will be: `action`, `suggestion`, `widget` or `shortcut` (depending on the source from which the search started). Also added the `other` option for the source but it should never enter on this case. |[1](https://github.com/mozilla-mobile/fenix/pull/1677), [2](https://github.com/mozilla-mobile/fenix/pull/5216), [3](https://github.com/mozilla-mobile/fenix/pull/7310)||2020-10-01 |1, 2 | +| metrics.search_widget_installed |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |Whether or not the search widget is installed |[1](https://github.com/mozilla-mobile/fenix/pull/10958)||2020-10-01 |2 | +| metrics.tabs_open_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many NORMAL tabs a user has open. This value will only be set if the user has at least *one* open tab. If they have 0, this ping will not get sent, resulting in a null value. To disambiguate between a failed `tabs_open_count` ping and 0 open tabs, please see `has_open_tabs`. |[1](https://github.com/mozilla-mobile/fenix/pull/12024)||2020-10-01 |2 | +| metrics.toolbar_position |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |A string that indicates the new position of the toolbar TOP or BOTTOM |[1](https://github.com/mozilla-mobile/fenix/pull/6608)||2020-10-01 |2 | +| metrics.top_sites_count |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |A counter that indicates how many top sites a user has. This value will only be set if the user has at least *one* top site. If they have 0, this ping will not get sent, resulting in a null value. To disambiguate between a failed `top_sites_count` ping and 0 top sites, please see `has_top_sites`. |[1](https://github.com/mozilla-mobile/fenix/pull/9556)||2020-10-01 |2 | +| perf.awesomebar.bookmark_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a bookmarks awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| perf.awesomebar.clipboard_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a clipboard awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| perf.awesomebar.history_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a history awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| perf.awesomebar.search_engine_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a search engine awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| perf.awesomebar.session_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a session awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| perf.awesomebar.shortcuts_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a shortcuts awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| perf.awesomebar.synced_tabs_suggestions |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |Duration of a synced tabs awesomebar suggestion query. |[1](https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979)||2020-10-01 |1, 2 | +| preferences.accessibility_services |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has touch exploration or switch services enabled. These are built into the Android OS, not Fenix prefs. default: "" |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.open_links_in_a_private_tab |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled open links in a private tab. default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.open_links_in_app |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has the open links in apps feature enabled. default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11446)||2020-10-01 |2 | +| preferences.remote_debugging |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has remote debugging enabled default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.search_bookmarks |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled bookmark search suggestions default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.search_browsing_history |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled browsing history suggestions. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.search_suggestions_private |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled showing search suggestions in private mode. default: false (we prompt the user, asking them to make a selection) |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.show_clipboard_suggestions |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled clipboard search suggestions. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.show_search_shortcuts |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled search shortcuts. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.show_search_suggestions |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has search suggestions enabled default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.show_voice_search |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has enabled the voice search button. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.sync |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user is signed into FxA default: false |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.sync_items |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |The list of items the user has chosen to sync with FxA. default: "" if the user is signed out. Otherwise defaults to whatever is set in their FxA account. New accounts set: [bookmarks, history, passwords, tabs] |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.telemetry |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |Whether or not the user has telemetry enabled. Note we should never receive a "false" value for this since telemetry would not send in that case. default: true |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.theme |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |The theme the user has enabled. "light," "dark," "system," or "battery" default: "system" for API 28+, else "light" |[1](https://github.com/mozilla-mobile/fenix/pull/11446)||2020-10-01 |2 | +| preferences.toolbar_position |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |The position of the toolbar default: bottom (defaults to top if the user has accessibility services) |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| preferences.tracking_protection |[string_list](https://mozilla.github.io/glean/book/user/metrics/string_list.html) |What type of enhanced tracking protection the user has enabled. "standard," "strict," "custom," or "" (if disabled) default: "standard" |[1](https://github.com/mozilla-mobile/fenix/pull/11211)||2020-10-01 |2 | +| search.default_engine.code |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |If the search engine is pre-loaded with Fenix this value will be the search engine identifier. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be "custom" |[1](https://github.com/mozilla-mobile/fenix/pull/1606), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 |1, 2 | +| search.default_engine.name |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |If the search engine is pre-loaded with Fenix this value will be the search engine name. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be "custom" |[1](https://github.com/mozilla-mobile/fenix/pull/1606), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 |1, 2 | +| search.default_engine.submission_url |[string](https://mozilla.github.io/glean/book/user/metrics/string.html) |If the search engine is pre-loaded with Fenix this value will be he base URL we use to build the search query for the search engine. For example: https://mysearchengine.com/?query=%s. If it's a custom search engine (defined: https://github.com/mozilla-mobile/fenix/issues/1607) the value will be "custom" |[1](https://github.com/mozilla-mobile/fenix/pull/1606), [2](https://github.com/mozilla-mobile/fenix/pull/5216)||2020-10-01 |1, 2 | +| storage.stats.app_bytes |[memory_distribution](https://mozilla.github.io/glean/book/user/metrics/memory_distribution.html) |The size of the app's APK and related files as installed: this is expected to be larger than download size. This is the output of [StorageStats.getAppBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getAppBytes()) so see that for details. This value is only available on Android 8+. A similar value may be available on the Google Play dashboard: we can use this value to see if that value is reliable enough. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 |1, 2 | +| storage.stats.cache_bytes |[memory_distribution](https://mozilla.github.io/glean/book/user/metrics/memory_distribution.html) |The size of all cached data in the app. This is the output of [StorageStats.getCacheBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getCacheBytes()) so see that for details. This value is only available on Android 8+. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 |1, 2 | +| storage.stats.data_dir_bytes |[memory_distribution](https://mozilla.github.io/glean/book/user/metrics/memory_distribution.html) |The size of all data minus `cache_bytes`. This is the output of [StorageStats.getDataBytes](https://developer.android.com/reference/android/app/usage/StorageStats#getDataBytes()) except we subtract the value of `cache_bytes` so the cache is not measured redundantly; see that method for details. This value is only available on Android 8+. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 |1, 2 | +| storage.stats.query_stats_duration |[timing_distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) |How long it took to query the device for the StorageStats that contain the file size information. The docs say it may be expensive so we want to ensure it's not too expensive. This value is only available on Android 8+. |[1](https://github.com/mozilla-mobile/fenix/pull/12876#issuecomment-666770732)||2021-02-01 |1, 2 | ## startup-timeline @@ -341,10 +341,10 @@ The following metrics are added to the ping: | Name | Type | Description | Data reviews | Extras | Expiration | [Data Sensitivity](https://wiki.mozilla.org/Firefox/Data_Collection) | | --- | --- | --- | --- | --- | --- | --- | -| startup.timeline.clock_ticks_per_second |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |The number of clock tick time units that occur in one second on this particular device. This value is expected to be used in conjunction with the `framework_start` metric. |[1](https://github.com/mozilla-mobile/fenix/pull/9788#pullrequestreview-394228626)||2020-10-01 | | -| startup.timeline.framework_start |[timespan](https://mozilla.github.io/glean/book/user/metrics/timespan.html) |The duration the Android framework takes to start before letting us run code in `*Application.init`. This is calculated from `appInitTimestamp - processStartTimestamp`. `processStartTimestamp` is derived from the clock tick time unit, which is expected to be less granular than nanoseconds. Therefore, we convert and round our timestamps to clock ticks before computing the difference and convert back to nanoseconds to report. For debugging purposes, `clock_ticks_per_second`, which may vary between devices, is also reported as a metric |[1](https://github.com/mozilla-mobile/fenix/pull/9788#pullrequestreview-394228626)||2020-10-01 | | -| startup.timeline.framework_start_error |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |An error when attempting to record `framework_start` - the application init timestamp returned a negative value - which is likely indicative of a bug in the implementation. |[1](https://github.com/mozilla-mobile/fenix/pull/9788#pullrequestreview-394228626)||2020-10-01 | | -| startup.timeline.framework_start_read_error |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |An error when attempting to read stats from /proc pseudo-filesystem - privacy managers can block access to reading these files - the application will catch a file reading exception. |[1](https://github.com/mozilla-mobile/fenix/pull/10481)||2020-10-01 | | +| startup.timeline.clock_ticks_per_second |[counter](https://mozilla.github.io/glean/book/user/metrics/counter.html) |The number of clock tick time units that occur in one second on this particular device. This value is expected to be used in conjunction with the `framework_start` metric. |[1](https://github.com/mozilla-mobile/fenix/pull/9788#pullrequestreview-394228626)||2020-10-01 |1 | +| startup.timeline.framework_start |[timespan](https://mozilla.github.io/glean/book/user/metrics/timespan.html) |The duration the Android framework takes to start before letting us run code in `*Application.init`. This is calculated from `appInitTimestamp - processStartTimestamp`. `processStartTimestamp` is derived from the clock tick time unit, which is expected to be less granular than nanoseconds. Therefore, we convert and round our timestamps to clock ticks before computing the difference and convert back to nanoseconds to report. For debugging purposes, `clock_ticks_per_second`, which may vary between devices, is also reported as a metric |[1](https://github.com/mozilla-mobile/fenix/pull/9788#pullrequestreview-394228626)||2020-10-01 |1 | +| startup.timeline.framework_start_error |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |An error when attempting to record `framework_start` - the application init timestamp returned a negative value - which is likely indicative of a bug in the implementation. |[1](https://github.com/mozilla-mobile/fenix/pull/9788#pullrequestreview-394228626)||2020-10-01 |1 | +| startup.timeline.framework_start_read_error |[boolean](https://mozilla.github.io/glean/book/user/metrics/boolean.html) |An error when attempting to read stats from /proc pseudo-filesystem - privacy managers can block access to reading these files - the application will catch a file reading exception. |[1](https://github.com/mozilla-mobile/fenix/pull/10481)||2020-10-01 |1 | Data categories are [defined here](https://wiki.mozilla.org/Firefox/Data_Collection). From f83372b67c43a42e6b4cd51f35855c8f301ceb96 Mon Sep 17 00:00:00 2001 From: Kate Glazko Date: Wed, 1 Jul 2020 16:10:44 -0700 Subject: [PATCH 010/128] For #349: View Downloads --- .../java/org/mozilla/fenix/FeatureFlags.kt | 5 + .../mozilla/fenix/components/metrics/Event.kt | 2 +- .../toolbar/BrowserToolbarController.kt | 8 ++ .../components/toolbar/DefaultToolbarMenu.kt | 9 ++ .../fenix/components/toolbar/ToolbarMenu.kt | 1 + .../org/mozilla/fenix/home/HomeFragment.kt | 9 ++ .../java/org/mozilla/fenix/home/HomeMenu.kt | 10 ++ .../library/downloads/DownloadAdapter.kt | 41 +++++++ .../library/downloads/DownloadController.kt | 31 +++++ .../library/downloads/DownloadFragment.kt | 108 ++++++++++++++++++ .../downloads/DownloadFragmentStore.kt | 61 ++++++++++ .../library/downloads/DownloadInteractor.kt | 29 +++++ .../fenix/library/downloads/DownloadView.kt | 74 ++++++++++++ .../DownloadsListItemViewHolder.kt | 46 ++++++++ .../main/res/drawable/ic_download_default.xml | 15 +++ .../main/res/layout/component_downloads.xml | 49 ++++++++ .../main/res/layout/download_list_item.xml | 17 +++ .../main/res/layout/fragment_downloads.xml | 12 ++ app/src/main/res/navigation/nav_graph.xml | 9 ++ app/src/main/res/values/strings.xml | 7 ++ .../library/downloads/DownloadAdapterTest.kt | 56 +++++++++ .../downloads/DownloadControllerTest.kt | 63 ++++++++++ .../downloads/DownloadInteractorTest.kt | 40 +++++++ 23 files changed, 701 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/DownloadInteractor.kt create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt create mode 100644 app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt create mode 100644 app/src/main/res/drawable/ic_download_default.xml create mode 100644 app/src/main/res/layout/component_downloads.xml create mode 100644 app/src/main/res/layout/download_list_item.xml create mode 100644 app/src/main/res/layout/fragment_downloads.xml create mode 100644 app/src/test/java/org/mozilla/fenix/library/downloads/DownloadAdapterTest.kt create mode 100644 app/src/test/java/org/mozilla/fenix/library/downloads/DownloadControllerTest.kt create mode 100644 app/src/test/java/org/mozilla/fenix/library/downloads/DownloadInteractorTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index c3b944f2e..1a3d4d01d 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -48,4 +48,9 @@ object FeatureFlags { * Enables downloads with external download managers. */ val externalDownloadManager = Config.channel.isNightlyOrDebug + + /** + * Enables viewing downloads in browser. + */ + val viewDownloads = Config.channel.isNightlyOrDebug } 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 83d5ef93d..6039adc8c 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 @@ -488,7 +488,7 @@ sealed class Event { NEW_PRIVATE_TAB, SHARE, BACK, FORWARD, RELOAD, STOP, OPEN_IN_FENIX, SAVE_TO_COLLECTION, ADD_TO_TOP_SITES, ADD_TO_HOMESCREEN, QUIT, READER_MODE_ON, READER_MODE_OFF, OPEN_IN_APP, BOOKMARK, READER_MODE_APPEARANCE, ADDONS_MANAGER, - BOOKMARKS, HISTORY, SYNC_TABS + BOOKMARKS, HISTORY, SYNC_TABS, DOWNLOADS } override val extras: Map? diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt index 5fd5b8ec6..436b8136d 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt @@ -380,6 +380,13 @@ class DefaultBrowserToolbarController( BrowserFragmentDirections.actionGlobalHistoryFragment() ) } + + ToolbarMenu.Item.Downloads -> browserAnimator.captureEngineViewAndDrawStatically { + navController.nav( + R.id.browserFragment, + BrowserFragmentDirections.actionGlobalDownloadsFragment() + ) + } } } @@ -414,6 +421,7 @@ class DefaultBrowserToolbarController( ToolbarMenu.Item.AddonsManager -> Event.BrowserMenuItemTapped.Item.ADDONS_MANAGER ToolbarMenu.Item.Bookmarks -> Event.BrowserMenuItemTapped.Item.BOOKMARKS ToolbarMenu.Item.History -> Event.BrowserMenuItemTapped.Item.HISTORY + ToolbarMenu.Item.Downloads -> Event.BrowserMenuItemTapped.Item.DOWNLOADS } activity.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem)) 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 dc98afa23..2ee5693fe 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 @@ -179,6 +179,7 @@ class DefaultToolbarMenu( .shouldDeleteBrowsingDataOnQuit val menuItems = listOfNotNull( + if (FeatureFlags.viewDownloads) downloadsItem else null, historyItem, bookmarksItem, if (FeatureFlags.syncedTabs) syncedTabs else null, @@ -333,6 +334,14 @@ class DefaultToolbarMenu( onItemTapped.invoke(ToolbarMenu.Item.Bookmarks) } + val downloadsItem = BrowserMenuImageText( + "Downloads", + R.drawable.ic_download, + primaryTextColor() + ) { + onItemTapped.invoke(ToolbarMenu.Item.Downloads) + } + @ColorRes private fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.primaryText, context) diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt index 5a8d88b13..27b47c309 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarMenu.kt @@ -30,6 +30,7 @@ interface ToolbarMenu { object ReaderModeAppearance : Item() object Bookmarks : Item() object History : Item() + object Downloads : Item() } val menuBuilder: BrowserMenuBuilder diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index 1becb7b8d..a914d33b1 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -771,6 +771,15 @@ class HomeFragment : Fragment() { HomeFragmentDirections.actionGlobalHistoryFragment() ) } + + HomeMenu.Item.Downloads -> { + hideOnboardingIfNeeded() + nav( + R.id.homeFragment, + HomeFragmentDirections.actionGlobalDownloadsFragment() + ) + } + HomeMenu.Item.Help -> { hideOnboardingIfNeeded() (activity as HomeActivity).openToBrowserAndLoad( diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt index 1ab68040b..a90dc3b50 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt @@ -43,6 +43,7 @@ class HomeMenu( object SyncedTabs : Item() object History : Item() object Bookmarks : Item() + object Downloads : Item() object Quit : Item() object Sync : Item() } @@ -144,6 +145,14 @@ class HomeMenu( onItemTapped.invoke(Item.Help) } + val downloadsItem = BrowserMenuImageText( + "Downloads", + R.drawable.ic_download, + primaryTextColor + ) { + onItemTapped.invoke(Item.Downloads) + } + // Only query account manager if it has been initialized. // We don't want to cause its initialization just for this check. val accountAuthItem = if (context.components.backgroundServices.accountManagerAvailableQueue.isReady()) { @@ -161,6 +170,7 @@ class HomeMenu( if (FeatureFlags.syncedTabs) syncedTabsItem else null, bookmarksItem, historyItem, + if (FeatureFlags.viewDownloads) downloadsItem else null, BrowserMenuDivider(), addons, BrowserMenuDivider(), diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt new file mode 100644 index 000000000..95ce6f247 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt @@ -0,0 +1,41 @@ + +/* 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.library.downloads + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import org.mozilla.fenix.library.SelectionHolder +import org.mozilla.fenix.library.downloads.viewholders.DownloadsListItemViewHolder + +class DownloadAdapter( + private val downloadInteractor: DownloadInteractor +) : RecyclerView.Adapter(), SelectionHolder { + private var downloads: List = listOf() + private var mode: DownloadFragmentState.Mode = DownloadFragmentState.Mode.Normal + override val selectedItems get() = mode.selectedItems + + override fun getItemCount(): Int = downloads.size + override fun getItemViewType(position: Int): Int = DownloadsListItemViewHolder.LAYOUT_ID + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsListItemViewHolder { + val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false) + return DownloadsListItemViewHolder(view, downloadInteractor, this) + } + + fun updateMode(mode: DownloadFragmentState.Mode) { + this.mode = mode + } + + override fun onBindViewHolder(holder: DownloadsListItemViewHolder, position: Int) { + holder.bind(downloads[position]) + } + + fun updateDownloads(downloads: List) { + this.downloads = downloads + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt new file mode 100644 index 000000000..9cc676272 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.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.library.downloads + +import org.mozilla.fenix.browser.browsingmode.BrowsingMode + +interface DownloadController { + fun handleOpen(item: DownloadItem, mode: BrowsingMode? = null) + fun handleBackPressed(): Boolean +} + +class DefaultDownloadController( + private val store: DownloadFragmentStore, + private val openToFileManager: (item: DownloadItem, mode: BrowsingMode?) -> Unit +) : DownloadController { + override fun handleOpen(item: DownloadItem, mode: BrowsingMode?) { + openToFileManager(item, mode) + } + + override fun handleBackPressed(): Boolean { + return if (store.state.mode is DownloadFragmentState.Mode.Editing) { + store.dispatch(DownloadFragmentAction.ExitEditMode) + true + } else { + false + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt new file mode 100644 index 000000000..82ed98e0a --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt @@ -0,0 +1,108 @@ +/* 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.library.downloads + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.fragment_downloads.view.* +import kotlinx.coroutines.ExperimentalCoroutinesApi +import mozilla.components.feature.downloads.AbstractFetchDownloadService +import mozilla.components.lib.state.ext.consumeFrom +import mozilla.components.support.base.feature.UserInteractionHandler +import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.R +import org.mozilla.fenix.browser.browsingmode.BrowsingMode +import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.showToolbar +import org.mozilla.fenix.library.LibraryPageFragment + +@SuppressWarnings("TooManyFunctions", "LargeClass") +class DownloadFragment : LibraryPageFragment(), UserInteractionHandler { + private lateinit var downloadStore: DownloadFragmentStore + private lateinit var downloadView: DownloadView + private lateinit var downloadInteractor: DownloadInteractor + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_downloads, container, false) + + val items = requireComponents.core.store.state.downloads.map { + DownloadItem( + it.value.id, + it.value.fileName, + it.value.filePath, + it.value.contentLength.toString(), + it.value.contentType + ) + } + + downloadStore = StoreProvider.get(this) { + DownloadFragmentStore( + DownloadFragmentState( + items = items, + mode = DownloadFragmentState.Mode.Normal + ) + ) + } + + val downloadController: DownloadController = DefaultDownloadController( + downloadStore, + ::openItem + ) + downloadInteractor = DownloadInteractor( + downloadController + ) + downloadView = DownloadView(view.downloadsLayout, downloadInteractor) + + return view + } + + override val selectedItems get() = downloadStore.state.mode.selectedItems + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + requireComponents.analytics.metrics.track(Event.HistoryOpened) + + setHasOptionsMenu(false) + } + + @ExperimentalCoroutinesApi + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + consumeFrom(downloadStore) { + downloadView.update(it) + } + } + + override fun onResume() { + super.onResume() + showToolbar(getString(R.string.library_downloads)) + } + + override fun onBackPressed(): Boolean { + return downloadView.onBackPressed() + } + + private fun openItem(item: DownloadItem, mode: BrowsingMode? = null) { + + mode?.let { (activity as HomeActivity).browsingModeManager.mode = it } + context?.let { + AbstractFetchDownloadService.openFile( + context = it, + contentType = item.contentType, + filePath = item.filePath + ) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt new file mode 100644 index 000000000..2078064a7 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt @@ -0,0 +1,61 @@ +/* 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.library.downloads + +import mozilla.components.lib.state.Action +import mozilla.components.lib.state.State +import mozilla.components.lib.state.Store + +/** + * Class representing a history entry + * @property id Unique id of the download item + * @property fileName File name of the download item + * @property filePath Full path of the download item + * @property size The size in bytes of the download item + * @property contentType The type of file the download is + */ +data class DownloadItem(val id: Long, val fileName: String?, val filePath: String, val size: String, val contentType: String?) + +/** + * The [Store] for holding the [DownloadFragmentState] and applying [DownloadFragmentAction]s. + */ +class DownloadFragmentStore(initialState: DownloadFragmentState) : + Store(initialState, ::downloadStateReducer) + +/** + * Actions to dispatch through the `DownloadStore` to modify `DownloadState` through the reducer. + */ +sealed class DownloadFragmentAction : Action { + object ExitEditMode : DownloadFragmentAction() +} + +/** + * The state for the Download Screen + * @property items List of DownloadItem to display + * @property mode Current Mode of Download + */ +data class DownloadFragmentState( + val items: List, + val mode: Mode +) : State { + sealed class Mode { + open val selectedItems = emptySet() + + object Normal : Mode() + data class Editing(override val selectedItems: Set) : DownloadFragmentState.Mode() + } +} + +/** + * The DownloadState Reducer. + */ +private fun downloadStateReducer( + state: DownloadFragmentState, + action: DownloadFragmentAction +): DownloadFragmentState { + return when (action) { + is DownloadFragmentAction.ExitEditMode -> state.copy(mode = DownloadFragmentState.Mode.Normal) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadInteractor.kt new file mode 100644 index 000000000..244444634 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadInteractor.kt @@ -0,0 +1,29 @@ +/* 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.library.downloads +/** + * Interactor for the download screen + * Provides implementations for the DownloadViewInteractor + */ +@SuppressWarnings("TooManyFunctions") +class DownloadInteractor( + private val downloadController: DownloadController +) : DownloadViewInteractor { + override fun open(item: DownloadItem) { + downloadController.handleOpen(item) + } + + override fun select(item: DownloadItem) { + TODO("Not yet implemented") + } + + override fun deselect(item: DownloadItem) { + TODO("Not yet implemented") + } + + override fun onBackPressed(): Boolean { + return downloadController.handleBackPressed() + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt new file mode 100644 index 000000000..3261ee91e --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt @@ -0,0 +1,74 @@ + + +/* 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.library.downloads + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.SimpleItemAnimator +import kotlinx.android.synthetic.main.component_downloads.view.* +import mozilla.components.support.base.feature.UserInteractionHandler +import org.mozilla.fenix.R +import org.mozilla.fenix.library.LibraryPageView +import org.mozilla.fenix.library.SelectionInteractor + +/** + * Interface for the DownloadViewInteractor. This interface is implemented by objects that want + * to respond to user interaction on the DownloadView + */ +interface DownloadViewInteractor : SelectionInteractor { + + /** + * Called on backpressed to exit edit mode + */ + fun onBackPressed(): Boolean +} + +/** + * View that contains and configures the Downloads List + */ +class DownloadView( + container: ViewGroup, + val interactor: DownloadInteractor +) : LibraryPageView(container), UserInteractionHandler { + + val view: View = LayoutInflater.from(container.context) + .inflate(R.layout.component_downloads, container, true) + + var mode: DownloadFragmentState.Mode = DownloadFragmentState.Mode.Normal + private set + + val downloadAdapter = DownloadAdapter(interactor) + private val layoutManager = LinearLayoutManager(container.context) + + init { + view.download_list.apply { + layoutManager = this@DownloadView.layoutManager + adapter = downloadAdapter + (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false + } + } + + fun update(state: DownloadFragmentState) { + + view.swipe_refresh.isEnabled = + state.mode === DownloadFragmentState.Mode.Normal + mode = state.mode + + downloadAdapter.updateMode(state.mode) + downloadAdapter.updateDownloads(state.items) + + setUiForNormalMode( + context.getString(R.string.library_downloads) + ) + } + + override fun onBackPressed(): Boolean { + return interactor.onBackPressed() + } +} diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt new file mode 100644 index 000000000..4126b2cd7 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt @@ -0,0 +1,46 @@ +/* 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.library.downloads.viewholders + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.download_list_item.view.* +import kotlinx.android.synthetic.main.library_site_item.view.* +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.hideAndDisable +import org.mozilla.fenix.library.SelectionHolder +import org.mozilla.fenix.library.downloads.DownloadInteractor +import org.mozilla.fenix.library.downloads.DownloadItem +import mozilla.components.feature.downloads.toMegabyteString + +class DownloadsListItemViewHolder( + view: View, + private val downloadInteractor: DownloadInteractor, + private val selectionHolder: SelectionHolder +) : RecyclerView.ViewHolder(view) { + + private var item: DownloadItem? = null + + fun bind( + item: DownloadItem + ) { + itemView.download_layout.visibility = View.VISIBLE + itemView.download_layout.titleView.text = item.fileName + itemView.download_layout.urlView.text = item.size.toLong().toMegabyteString() + + itemView.download_layout.setSelectionInteractor(item, selectionHolder, downloadInteractor) + itemView.download_layout.changeSelected(item in selectionHolder.selectedItems) + + itemView.overflow_menu.hideAndDisable() + itemView.favicon.setImageResource(R.drawable.ic_download_default) + itemView.favicon.isClickable = false + + this.item = item + } + + companion object { + const val LAYOUT_ID = R.layout.download_list_item + } +} diff --git a/app/src/main/res/drawable/ic_download_default.xml b/app/src/main/res/drawable/ic_download_default.xml new file mode 100644 index 000000000..c7387d54b --- /dev/null +++ b/app/src/main/res/drawable/ic_download_default.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/layout/component_downloads.xml b/app/src/main/res/layout/component_downloads.xml new file mode 100644 index 000000000..a6bcbe35e --- /dev/null +++ b/app/src/main/res/layout/component_downloads.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/download_list_item.xml b/app/src/main/res/layout/download_list_item.xml new file mode 100644 index 000000000..7e9ddafd4 --- /dev/null +++ b/app/src/main/res/layout/download_list_item.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_downloads.xml b/app/src/main/res/layout/fragment_downloads.xml new file mode 100644 index 000000000..11fc15df2 --- /dev/null +++ b/app/src/main/res/layout/fragment_downloads.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index a142bf363..d8f6cef7d 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -70,6 +70,9 @@ + + @@ -239,6 +242,12 @@ android:label="@string/library_history" tools:layout="@layout/fragment_history" /> + + No history here + + + No downloads here + + %1$d selected + Sorry. %1$s can’t load that page. diff --git a/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadAdapterTest.kt b/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadAdapterTest.kt new file mode 100644 index 000000000..79ba1a8ab --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadAdapterTest.kt @@ -0,0 +1,56 @@ +/* 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.library.downloads + +import androidx.recyclerview.widget.RecyclerView +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.verify +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner + +@RunWith(FenixRobolectricTestRunner::class) +class DownloadAdapterTest { + + private lateinit var interactor: DownloadInteractor + private lateinit var adapter: DownloadAdapter + + @Before + fun setup() { + interactor = mockk() + adapter = DownloadAdapter(interactor) + + every { interactor.select(any()) } just Runs + } + + @Test + fun `getItemCount should return the number of tab collections`() { + val download = mockk() + + assertEquals(0, adapter.itemCount) + + adapter.updateDownloads( + downloads = listOf(download) + ) + assertEquals(1, adapter.itemCount) + } + + @Test + fun `updateData inserts item`() { + val download = mockk { + } + val observer = mockk(relaxed = true) + adapter.registerAdapterDataObserver(observer) + adapter.updateDownloads( + downloads = listOf(download) + ) + verify { observer.onChanged() } + } +} diff --git a/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadControllerTest.kt b/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadControllerTest.kt new file mode 100644 index 000000000..68ae555dd --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadControllerTest.kt @@ -0,0 +1,63 @@ +/* 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.library.downloads + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineScope +import org.junit.Assert.assertFalse +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.browser.browsingmode.BrowsingMode +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner + +@ExperimentalCoroutinesApi +@RunWith(FenixRobolectricTestRunner::class) +class DownloadControllerTest { + private val downloadItem = DownloadItem(0, "title", "url", "77", "jpg") + private val scope: CoroutineScope = TestCoroutineScope() + private val store: DownloadFragmentStore = mockk(relaxed = true) + private val state: DownloadFragmentState = mockk(relaxed = true) + private val openToFileManager: (DownloadItem, BrowsingMode?) -> Unit = mockk(relaxed = true) + private val invalidateOptionsMenu: () -> Unit = mockk(relaxed = true) + private val controller = DefaultDownloadController( + store, + openToFileManager + ) + + @Before + fun setUp() { + every { store.state } returns state + } + + @Test + fun onPressDownloadItemInNormalMode() { + controller.handleOpen(downloadItem) + + verify { + openToFileManager(downloadItem, null) + } + } + + @Test + fun onOpenItemInNormalMode() { + controller.handleOpen(downloadItem, BrowsingMode.Normal) + + verify { + openToFileManager(downloadItem, BrowsingMode.Normal) + } + } + + @Test + fun onBackPressedInNormalMode() { + every { state.mode } returns DownloadFragmentState.Mode.Normal + + assertFalse(controller.handleBackPressed()) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadInteractorTest.kt new file mode 100644 index 000000000..3e552d6ab --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/library/downloads/DownloadInteractorTest.kt @@ -0,0 +1,40 @@ +/* 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.library.downloads + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verifyAll +import org.junit.Assert.assertTrue +import org.junit.Test + +class DownloadInteractorTest { + private val downloadItem = DownloadItem(0, "title", "url", "5.6 mb", "png") + val controller: DownloadController = mockk(relaxed = true) + val interactor = DownloadInteractor(controller) + + @Test + fun onOpen() { + interactor.open(downloadItem) + + verifyAll { + controller.handleOpen(downloadItem) + } + } + + @Test + fun onBackPressed() { + every { + controller.handleBackPressed() + } returns true + + val backpressHandled = interactor.onBackPressed() + + verifyAll { + controller.handleBackPressed() + } + assertTrue(backpressHandled) + } +} From 2e62dd5c874e3c88edaae21b1bb5f2a548d1d27a Mon Sep 17 00:00:00 2001 From: Elise Richards Date: Wed, 19 Aug 2020 13:24:48 -0500 Subject: [PATCH 011/128] =?UTF-8?q?FNX-14546=20=E2=81=83=20For=20#13096:?= =?UTF-8?q?=20Add=20notifications=20pref=20in=20top=20level=20settings=20(?= =?UTF-8?q?#13366)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add notifications pref in top level settings to route to Android app and notification settings * Make pref visible on Oreo and higher * Only show notifications pref when Oreo and above --- .../org/mozilla/fenix/settings/SettingsFragment.kt | 11 +++++++++++ app/src/main/java/org/mozilla/fenix/utils/Settings.kt | 1 + app/src/main/res/values/preference_keys.xml | 1 + app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/preferences.xml | 5 +++++ 5 files changed, 20 insertions(+) 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 f74e27bb4..38dc05b83 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -270,6 +270,13 @@ class SettingsFragment : PreferenceFragmentCompat() { resources.getString(R.string.pref_key_delete_browsing_data_on_quit_preference) -> { SettingsFragmentDirections.actionSettingsFragmentToDeleteBrowsingDataOnQuitFragment() } + resources.getString(R.string.pref_key_notifications) -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) + startActivity(intent) + } + null + } resources.getString(R.string.pref_key_customize) -> { SettingsFragmentDirections.actionSettingsFragmentToCustomizationFragment() } @@ -352,6 +359,10 @@ class SettingsFragment : PreferenceFragmentCompat() { findPreference( getPreferenceKey(R.string.pref_key_debug_settings) )?.isVisible = requireContext().settings().showSecretDebugMenuThisSession + + findPreference( + getPreferenceKey(R.string.pref_key_notifications) + )?.isVisible = requireContext().settings().showNotificationsSetting } private fun getClickListenerForMakeDefaultBrowser(): Preference.OnPreferenceClickListener { diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index ba2390b3f..6c703a9c2 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -279,6 +279,7 @@ class Settings(private val appContext: Context) : PreferencesHolder { !trackingProtectionOnboardingShownThisSession) var showSecretDebugMenuThisSession = false + var showNotificationsSetting = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O val shouldShowSecurityPinWarningSync: Boolean get() = loginsSecureWarningSyncCount < showLoginsSecureWarningSyncMaxCount diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 317651afd..57402d075 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -20,6 +20,7 @@ pref_key_privacy_link pref_key_delete_browsing_data pref_key_delete_browsing_data_on_quit_preference + pref_key_notifications pref_key_delete_browsing_data_on_quit pref_key_delete_open_tabs_on_quit pref_key_delete_browsing_history_on_quit diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c1d3b87b6..3b3e512f7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -300,6 +300,8 @@ External download manager Add-ons + + Notifications diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index f3bf4c39b..c161e4c96 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -109,6 +109,11 @@ android:key="@string/pref_key_delete_browsing_data_on_quit_preference" android:title="@string/preferences_delete_browsing_data_on_quit" /> + + Date: Tue, 18 Aug 2020 00:09:27 -0400 Subject: [PATCH 012/128] For #12287: Add Synced Tabs to Tabs Tray --- .../org/mozilla/fenix/BrowserDirection.kt | 3 +- .../java/org/mozilla/fenix/HomeActivity.kt | 3 + .../mozilla/fenix/sync/SyncedTabsAdapter.kt | 54 ++++++++--- .../mozilla/fenix/sync/SyncedTabsLayout.kt | 44 ++++----- .../fenix/sync/SyncedTabsViewHolder.kt | 49 ++++++++-- .../org/mozilla/fenix/sync/ext/ErrorType.kt | 38 ++++++++ .../fenix/sync/ext/SyncedTabsAdapter.kt | 22 +++++ .../fenix/tabtray/SyncedTabsController.kt | 55 +++++++++++ .../fenix/tabtray/TabTrayController.kt | 12 +++ .../fenix/tabtray/TabTrayDialogFragment.kt | 3 +- .../tabtray/TabTrayFragmentInteractor.kt | 10 ++ .../org/mozilla/fenix/tabtray/TabTrayView.kt | 58 +++++++++--- app/src/main/res/anim/full_rotation.xml | 9 ++ .../main/res/layout/sync_tabs_error_row.xml | 1 + .../res/layout/view_synced_tabs_no_item.xml | 9 ++ .../res/layout/view_synced_tabs_title.xml | 29 ++++++ .../fenix/sync/ListenerDelegateTest.kt | 26 ++++++ .../fenix/sync/SyncedTabsAdapterTest.kt | 13 ++- .../fenix/sync/SyncedTabsLayoutTest.kt | 75 --------------- .../fenix/sync/SyncedTabsViewHolderTest.kt | 41 ++++++++- .../mozilla/fenix/sync/ext/ErrorTypeKtTest.kt | 72 +++++++++++++++ .../fenix/sync/ext/SyncedTabsAdapterKtTest.kt | 92 +++++++++++++++++++ .../tabtray/DefaultTabTrayControllerTest.kt | 13 +++ .../fenix/tabtray/SyncedTabsControllerTest.kt | 78 ++++++++++++++++ .../tabtray/TabTrayFragmentInteractorTest.kt | 6 ++ 25 files changed, 674 insertions(+), 141 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/sync/ext/ErrorType.kt create mode 100644 app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt create mode 100644 app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt create mode 100644 app/src/main/res/anim/full_rotation.xml create mode 100644 app/src/main/res/layout/view_synced_tabs_no_item.xml create mode 100644 app/src/main/res/layout/view_synced_tabs_title.xml create mode 100644 app/src/test/java/org/mozilla/fenix/sync/ListenerDelegateTest.kt create mode 100644 app/src/test/java/org/mozilla/fenix/sync/ext/ErrorTypeKtTest.kt create mode 100644 app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt create mode 100644 app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt b/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt index f23c51c31..841305b36 100644 --- a/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt +++ b/app/src/main/java/org/mozilla/fenix/BrowserDirection.kt @@ -31,5 +31,6 @@ enum class BrowserDirection(@IdRes val fragmentId: Int) { FromEditCustomSearchEngineFragment(R.id.editCustomSearchEngineFragment), FromAddonDetailsFragment(R.id.addonDetailsFragment), FromAddonPermissionsDetailsFragment(R.id.addonPermissionsDetailFragment), - FromLoginDetailFragment(R.id.loginDetailFragment) + FromLoginDetailFragment(R.id.loginDetailFragment), + FromTabTray(R.id.tabTrayDialogFragment) } diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index 02496dca7..86f26ed9e 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -100,6 +100,7 @@ import org.mozilla.fenix.settings.search.EditCustomSearchEngineFragmentDirection import org.mozilla.fenix.share.AddNewDeviceFragmentDirections import org.mozilla.fenix.sync.SyncedTabsFragmentDirections import org.mozilla.fenix.tabtray.TabTrayDialogFragment +import org.mozilla.fenix.tabtray.TabTrayDialogFragmentDirections import org.mozilla.fenix.theme.DefaultThemeManager import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.BrowsersCache @@ -597,6 +598,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { AddonPermissionsDetailsFragmentDirections.actionGlobalBrowser(customTabSessionId) BrowserDirection.FromLoginDetailFragment -> LoginDetailFragmentDirections.actionGlobalBrowser(customTabSessionId) + BrowserDirection.FromTabTray -> + TabTrayDialogFragmentDirections.actionGlobalBrowser(customTabSessionId) } /** diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt index e51419df4..6e30a4711 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt @@ -10,14 +10,18 @@ import androidx.navigation.NavController import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import mozilla.components.browser.storage.sync.SyncedDeviceTabs +import mozilla.components.feature.syncedtabs.view.SyncedTabsView import org.mozilla.fenix.sync.SyncedTabsViewHolder.DeviceViewHolder import org.mozilla.fenix.sync.SyncedTabsViewHolder.ErrorViewHolder +import org.mozilla.fenix.sync.SyncedTabsViewHolder.NoTabsViewHolder import org.mozilla.fenix.sync.SyncedTabsViewHolder.TabViewHolder +import org.mozilla.fenix.sync.SyncedTabsViewHolder.TitleViewHolder +import org.mozilla.fenix.sync.ext.toAdapterList import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.concept.sync.Device as SyncDevice class SyncedTabsAdapter( - private val listener: (SyncTab) -> Unit + private val newListener: SyncedTabsView.Listener ) : ListAdapter(DiffCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SyncedTabsViewHolder { @@ -27,30 +31,26 @@ class SyncedTabsAdapter( DeviceViewHolder.LAYOUT_ID -> DeviceViewHolder(itemView) TabViewHolder.LAYOUT_ID -> TabViewHolder(itemView) ErrorViewHolder.LAYOUT_ID -> ErrorViewHolder(itemView) + TitleViewHolder.LAYOUT_ID -> TitleViewHolder(itemView) + NoTabsViewHolder.LAYOUT_ID -> NoTabsViewHolder(itemView) else -> throw IllegalStateException() } } override fun onBindViewHolder(holder: SyncedTabsViewHolder, position: Int) { - holder.bind(getItem(position), listener) + holder.bind(getItem(position), newListener) } override fun getItemViewType(position: Int) = when (getItem(position)) { is AdapterItem.Device -> DeviceViewHolder.LAYOUT_ID is AdapterItem.Tab -> TabViewHolder.LAYOUT_ID is AdapterItem.Error -> ErrorViewHolder.LAYOUT_ID + is AdapterItem.Title -> TitleViewHolder.LAYOUT_ID + is AdapterItem.NoTabs -> NoTabsViewHolder.LAYOUT_ID } fun updateData(syncedTabs: List) { - val allDeviceTabs = mutableListOf() - - syncedTabs.forEach { (device, tabs) -> - if (tabs.isNotEmpty()) { - allDeviceTabs.add(AdapterItem.Device(device)) - tabs.mapTo(allDeviceTabs) { AdapterItem.Tab(it) } - } - } - + val allDeviceTabs = syncedTabs.toAdapterList() submitList(allDeviceTabs) } @@ -59,7 +59,11 @@ class SyncedTabsAdapter( when (oldItem) { is AdapterItem.Device -> newItem is AdapterItem.Device && oldItem.device.id == newItem.device.id - is AdapterItem.Tab, is AdapterItem.Error -> + is AdapterItem.NoTabs -> + newItem is AdapterItem.NoTabs && oldItem.device.id == newItem.device.id + is AdapterItem.Tab, + is AdapterItem.Error, + is AdapterItem.Title -> oldItem == newItem } @@ -68,9 +72,35 @@ class SyncedTabsAdapter( oldItem == newItem } + /** + * The various types of adapter items that can be found in a [SyncedTabsAdapter]. + */ sealed class AdapterItem { + + /** + * A title header of the Synced Tabs UI that has a refresh button in it. This may be seen + * only in some views depending on where the Synced Tabs UI is displayed. + */ + object Title : AdapterItem() + + /** + * A device header for displaying a synced device. + */ data class Device(val device: SyncDevice) : AdapterItem() + + /** + * A tab that was synced. + */ data class Tab(val tab: SyncTab) : AdapterItem() + + /** + * A placeholder for a device that has no tabs synced. + */ + data class NoTabs(val device: SyncDevice) : AdapterItem() + + /** + * A message displayed if an error was encountered. + */ data class Error( val descriptionResId: Int, val navController: NavController? = null diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt index 8308692ba..1d160cfe5 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.sync import android.content.Context import android.util.AttributeSet import android.widget.FrameLayout -import androidx.annotation.StringRes import androidx.fragment.app.findFragment import androidx.navigation.NavController import androidx.navigation.fragment.findNavController @@ -18,8 +17,11 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import mozilla.components.browser.storage.sync.SyncedDeviceTabs +import mozilla.components.browser.storage.sync.Tab import mozilla.components.feature.syncedtabs.view.SyncedTabsView import org.mozilla.fenix.R +import org.mozilla.fenix.sync.ext.toAdapterItem +import org.mozilla.fenix.sync.ext.toStringRes import java.lang.IllegalStateException class SyncedTabsLayout @JvmOverloads constructor( @@ -30,7 +32,7 @@ class SyncedTabsLayout @JvmOverloads constructor( override var listener: SyncedTabsView.Listener? = null - private val adapter = SyncedTabsAdapter { listener?.onTabClicked(it) } + private val adapter = SyncedTabsAdapter(ListenerDelegate { listener }) private val coroutineScope = CoroutineScope(Dispatchers.Main) init { @@ -53,8 +55,8 @@ class SyncedTabsLayout @JvmOverloads constructor( null } - val descriptionResId = stringResourceForError(error) - val errorItem = getErrorItem(navController, error, descriptionResId) + val descriptionResId = error.toStringRes() + val errorItem = error.toAdapterItem(descriptionResId, navController) val errorList: List = listOf(errorItem) adapter.submitList(errorList) @@ -96,27 +98,21 @@ class SyncedTabsLayout @JvmOverloads constructor( SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE, SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> true } + } +} - internal fun stringResourceForError(error: SyncedTabsView.ErrorType) = when (error) { - SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE -> R.string.synced_tabs_connect_another_device - SyncedTabsView.ErrorType.SYNC_ENGINE_UNAVAILABLE -> R.string.synced_tabs_enable_tab_syncing - SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> R.string.synced_tabs_sign_in_message - SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION -> R.string.synced_tabs_reauth - SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> R.string.synced_tabs_no_tabs - } +/** + * We have to do this weird daisy-chaining of callbacks because the listener is nullable and + * when we get a null reference, we never get a new binding to the non-null listener. + */ +class ListenerDelegate( + private val listener: (() -> SyncedTabsView.Listener?) +) : SyncedTabsView.Listener { + override fun onRefresh() { + listener.invoke()?.onRefresh() + } - internal fun getErrorItem( - navController: NavController?, - error: SyncedTabsView.ErrorType, - @StringRes stringResId: Int - ): SyncedTabsAdapter.AdapterItem = when (error) { - SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE, - SyncedTabsView.ErrorType.SYNC_ENGINE_UNAVAILABLE, - SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION, - SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> SyncedTabsAdapter.AdapterItem - .Error(descriptionResId = stringResId) - SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> SyncedTabsAdapter.AdapterItem - .Error(descriptionResId = stringResId, navController = navController) - } + override fun onTabClicked(tab: Tab) { + listener.invoke()?.onTabClicked(tab) } } diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt index 95abada88..4549f570e 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt @@ -7,29 +7,36 @@ package org.mozilla.fenix.sync import android.view.View import android.view.View.GONE import android.view.View.VISIBLE +import android.view.animation.Animation +import android.view.animation.AnimationUtils import android.widget.LinearLayout import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.sync_tabs_error_row.view.* import kotlinx.android.synthetic.main.sync_tabs_list_item.view.* import kotlinx.android.synthetic.main.view_synced_tabs_group.view.* -import mozilla.components.browser.storage.sync.Tab +import kotlinx.android.synthetic.main.view_synced_tabs_title.view.* import mozilla.components.concept.sync.DeviceType +import mozilla.components.feature.syncedtabs.view.SyncedTabsView import mozilla.components.support.ktx.android.util.dpToPx import org.mozilla.fenix.NavGraphDirections import org.mozilla.fenix.R import org.mozilla.fenix.sync.SyncedTabsAdapter.AdapterItem +/** + * The various view-holders that can be found in a [SyncedTabsAdapter]. For more + * descriptive information on the different types, see the docs for [AdapterItem]. + */ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - abstract fun bind(item: T, interactor: (Tab) -> Unit) + abstract fun bind(item: T, interactor: SyncedTabsView.Listener) class TabViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { - override fun bind(item: T, interactor: (Tab) -> Unit) { + override fun bind(item: T, interactor: SyncedTabsView.Listener) { bindTab(item as AdapterItem.Tab) itemView.setOnClickListener { - interactor(item.tab) + interactor.onTabClicked(item.tab) } } @@ -46,7 +53,7 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item class ErrorViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { - override fun bind(item: T, interactor: (Tab) -> Unit) { + override fun bind(item: T, interactor: SyncedTabsView.Listener) { val errorItem = item as AdapterItem.Error setErrorMargins() @@ -69,7 +76,7 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item class DeviceViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { - override fun bind(item: T, interactor: (Tab) -> Unit) { + override fun bind(item: T, interactor: SyncedTabsView.Listener) { bindHeader(item as AdapterItem.Device) } @@ -93,6 +100,36 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item } } + class NoTabsViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { + override fun bind(item: T, interactor: SyncedTabsView.Listener) = Unit + + companion object { + const val LAYOUT_ID = R.layout.view_synced_tabs_no_item + } + } + + class TitleViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { + + override fun bind(item: T, interactor: SyncedTabsView.Listener) { + itemView.refresh_icon.setOnClickListener { v -> + val rotation = AnimationUtils.loadAnimation( + itemView.context, + R.anim.full_rotation + ).apply { + repeatCount = Animation.ABSOLUTE + } + + v.startAnimation(rotation) + + interactor.onRefresh() + } + } + + companion object { + const val LAYOUT_ID = R.layout.view_synced_tabs_title + } + } + internal fun setErrorMargins() { val lp = LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, diff --git a/app/src/main/java/org/mozilla/fenix/sync/ext/ErrorType.kt b/app/src/main/java/org/mozilla/fenix/sync/ext/ErrorType.kt new file mode 100644 index 000000000..1a24ba455 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/sync/ext/ErrorType.kt @@ -0,0 +1,38 @@ +/* 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.sync.ext + +import androidx.annotation.StringRes +import androidx.navigation.NavController +import mozilla.components.feature.syncedtabs.view.SyncedTabsView.ErrorType +import org.mozilla.fenix.R +import org.mozilla.fenix.sync.SyncedTabsAdapter + +/** + * Converts the error type to the appropriate matching string resource for displaying to the user. + */ +fun ErrorType.toStringRes() = when (this) { + ErrorType.MULTIPLE_DEVICES_UNAVAILABLE -> R.string.synced_tabs_connect_another_device + ErrorType.SYNC_ENGINE_UNAVAILABLE -> R.string.synced_tabs_enable_tab_syncing + ErrorType.SYNC_UNAVAILABLE -> R.string.synced_tabs_sign_in_message + ErrorType.SYNC_NEEDS_REAUTHENTICATION -> R.string.synced_tabs_reauth + ErrorType.NO_TABS_AVAILABLE -> R.string.synced_tabs_no_tabs +} + +/** + * Converts an error type to an [SyncedTabsAdapter.AdapterItem.Error]. + */ +fun ErrorType.toAdapterItem( + @StringRes stringResId: Int, + navController: NavController? = null +) = when (this) { + ErrorType.MULTIPLE_DEVICES_UNAVAILABLE, + ErrorType.SYNC_ENGINE_UNAVAILABLE, + ErrorType.SYNC_NEEDS_REAUTHENTICATION, + ErrorType.NO_TABS_AVAILABLE -> SyncedTabsAdapter.AdapterItem + .Error(descriptionResId = stringResId) + ErrorType.SYNC_UNAVAILABLE -> SyncedTabsAdapter.AdapterItem + .Error(descriptionResId = stringResId, navController = navController) +} diff --git a/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt new file mode 100644 index 000000000..6f1e982b5 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt @@ -0,0 +1,22 @@ +/* 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.sync.ext + +import mozilla.components.browser.storage.sync.SyncedDeviceTabs +import org.mozilla.fenix.sync.SyncedTabsAdapter.AdapterItem + +fun List.toAdapterList( +): MutableList { + val allDeviceTabs = mutableListOf() + + forEach { (device, tabs) -> + if (tabs.isNotEmpty()) { + allDeviceTabs.add(AdapterItem.Device(device)) + tabs.mapTo(allDeviceTabs) { AdapterItem.Tab(it) } + } + } + + return allDeviceTabs +} \ No newline at end of file diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt b/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt new file mode 100644 index 000000000..2e47fff15 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt @@ -0,0 +1,55 @@ +/* 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.tabtray + +import android.view.View +import androidx.fragment.app.FragmentManager.findFragment +import androidx.navigation.NavController +import androidx.navigation.fragment.findNavController +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import mozilla.components.browser.storage.sync.SyncedDeviceTabs +import mozilla.components.feature.syncedtabs.view.SyncedTabsView +import org.mozilla.fenix.sync.ListenerDelegate +import org.mozilla.fenix.sync.SyncedTabsAdapter +import org.mozilla.fenix.sync.ext.toAdapterList +import org.mozilla.fenix.sync.ext.toAdapterItem +import org.mozilla.fenix.sync.ext.toStringRes +import kotlin.coroutines.CoroutineContext + +class SyncedTabsController( + private val view: View, + coroutineContext: CoroutineContext = Dispatchers.Main +) : SyncedTabsView { + override var listener: SyncedTabsView.Listener? = null + + val adapter = SyncedTabsAdapter(ListenerDelegate { listener }) + + private val scope: CoroutineScope = CoroutineScope(coroutineContext) + + override fun displaySyncedTabs(syncedTabs: List) { + scope.launch { + val tabsList = listOf(SyncedTabsAdapter.AdapterItem.Title) + syncedTabs.toAdapterList() + // Reverse layout for TabTrayView which does things backwards. + adapter.submitList(tabsList.reversed()) + } + } + + override fun onError(error: SyncedTabsView.ErrorType) { + scope.launch { + val navController: NavController? = try { + findFragment(view).findNavController() + } catch (exception: IllegalStateException) { + null + } + + val descriptionResId = error.toStringRes() + val errorItem = error.toAdapterItem(descriptionResId, navController) + + adapter.submitList(listOf(errorItem)) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt index ad71ced1c..7a3a03eee 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt @@ -9,10 +9,12 @@ import androidx.navigation.NavController import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager +import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.concept.engine.profiler.Profiler import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.tabstray.Tab import mozilla.components.feature.tabs.TabsUseCases +import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager @@ -30,6 +32,7 @@ interface TabTrayController { fun onNewTabTapped(private: Boolean) fun onTabTrayDismissed() fun onShareTabsClicked(private: Boolean) + fun onSyncedTabClicked(syncTab: SyncTab) fun onSaveToCollectionClicked(selectedTabs: Set) fun onCloseAllTabsClicked(private: Boolean) fun handleBackPressed(): Boolean @@ -59,6 +62,7 @@ interface TabTrayController { */ @Suppress("TooManyFunctions") class DefaultTabTrayController( + private val activity: HomeActivity, private val profiler: Profiler?, private val sessionManager: SessionManager, private val browsingModeManager: BrowsingModeManager, @@ -117,6 +121,14 @@ class DefaultTabTrayController( navController.navigate(directions) } + override fun onSyncedTabClicked(syncTab: SyncTab) { + activity.openToBrowserAndLoad( + searchTermOrURL = syncTab.active().url, + newTab = true, + from = BrowserDirection.FromTabTray + ) + } + @OptIn(ExperimentalCoroutinesApi::class) override fun onCloseAllTabsClicked(private: Boolean) { val sessionsToClose = if (private) { diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt index cfe8b0f1c..be5ec1818 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt @@ -177,6 +177,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler adapter, interactor = TabTrayFragmentInteractor( DefaultTabTrayController( + activity = activity, profiler = activity.components.core.engine.profiler, sessionManager = activity.components.core.sessionManager, browsingModeManager = activity.browsingModeManager, @@ -194,7 +195,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler isPrivate = isPrivate, startingInLandscape = requireContext().resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE, - lifecycleScope = viewLifecycleOwner.lifecycleScope + lifecycleOwner = viewLifecycleOwner ) { private -> val filter: (TabSessionState) -> Boolean = { state -> private == state.content.private } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt index 33bef403a..b6a65dd77 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.tabtray import mozilla.components.concept.tabstray.Tab +import mozilla.components.browser.storage.sync.Tab as SyncTab @Suppress("TooManyFunctions") interface TabTrayInteractor { @@ -33,6 +34,11 @@ interface TabTrayInteractor { */ fun onCloseAllTabsClicked(private: Boolean) + /** + * Called when the user clicks on a synced tab entry. + */ + fun onSyncedTabClicked(syncTab: SyncTab) + /** * Called when the physical back button is clicked. */ @@ -89,6 +95,10 @@ class TabTrayFragmentInteractor(private val controller: TabTrayController) : Tab controller.onCloseAllTabsClicked(private) } + override fun onSyncedTabClicked(syncTab: SyncTab) { + controller.onSyncedTabClicked(syncTab) + } + override fun onBackPressed(): Boolean { return controller.handleBackPressed() } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt index 9b78836ff..977cee49a 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt @@ -16,7 +16,8 @@ import androidx.constraintlayout.widget.ConstraintSet import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams -import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -35,7 +36,10 @@ import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.selector.privateTabs import mozilla.components.browser.state.state.BrowserState +import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.browser.tabstray.TabViewHolder +import mozilla.components.feature.syncedtabs.SyncedTabsFeature +import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.ktx.android.util.dpToPx import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event @@ -58,9 +62,10 @@ class TabTrayView( private val interactor: TabTrayInteractor, isPrivate: Boolean, startingInLandscape: Boolean, - lifecycleScope: LifecycleCoroutineScope, + lifecycleOwner: LifecycleOwner, private val filterTabs: (Boolean) -> Unit ) : LayoutContainer, TabLayout.OnTabSelectedListener { + val lifecycleScope = lifecycleOwner.lifecycleScope val fabView = LayoutInflater.from(container.context) .inflate(R.layout.component_tabstray_fab, container, true) @@ -79,13 +84,18 @@ class TabTrayView( private var tabsTouchHelper: TabsTouchHelper private val collectionsButtonAdapter = SaveToCollectionsButtonAdapter(interactor, isPrivate) + private val syncedTabsController = SyncedTabsController(view) + private val syncedTabsFeature = ViewBoundFeatureWrapper() + private var hasLoaded = false override val containerView: View? get() = container + private val components = container.context.components + init { - container.context.components.analytics.metrics.track(Event.TabsTrayOpened) + components.analytics.metrics.track(Event.TabsTrayOpened) toggleFabText(isPrivate) @@ -102,7 +112,7 @@ class TabTrayView( override fun onStateChanged(bottomSheet: View, newState: Int) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { - container.context.components.analytics.metrics.track(Event.TabsTrayClosed) + components.analytics.metrics.track(Event.TabsTrayClosed) interactor.onTabTrayDismissed() } } @@ -135,8 +145,20 @@ class TabTrayView( setTopOffset(startingInLandscape) - val concatAdapter = ConcatAdapter(tabsAdapter) + syncedTabsFeature.set( + feature = SyncedTabsFeature( + context = container.context, + storage = components.backgroundServices.syncedTabsStorage, + accountManager = components.backgroundServices.accountManager, + view = syncedTabsController, + lifecycleOwner = lifecycleOwner, + onTabClicked = ::handleTabClicked + ), + owner = lifecycleOwner, + view = view + ) + val concatAdapter = ConcatAdapter(tabsAdapter) view.tabsTray.apply { layoutManager = LinearLayoutManager(container.context).apply { reverseLayout = true @@ -156,6 +178,9 @@ class TabTrayView( // Put the 'Add to collections' button after the tabs have loaded. concatAdapter.addAdapter(0, collectionsButtonAdapter) + // Put the Synced Tabs adapter at the end. + concatAdapter.addAdapter(0, syncedTabsController.adapter) + if (hasAccessibilityEnabled) { tabsAdapter.notifyDataSetChanged() } @@ -193,7 +218,7 @@ class TabTrayView( } view.tab_tray_overflow.setOnClickListener { - container.context.components.analytics.metrics.track(Event.TabsTrayMenuOpened) + components.analytics.metrics.track(Event.TabsTrayMenuOpened) menu = tabTrayItemMenu.menuBuilder.build(container.context) menu?.show(it) ?.also { pu -> @@ -209,6 +234,10 @@ class TabTrayView( adjustNewTabButtonsForNormalMode() } + private fun handleTabClicked(tab: SyncTab) { + interactor.onSyncedTabClicked(tab) + } + private fun adjustNewTabButtonsForNormalMode() { view.tab_tray_new_tab.apply { isVisible = hasAccessibilityEnabled @@ -234,7 +263,7 @@ class TabTrayView( Event.NewTabTapped } - container.context.components.analytics.metrics.track(eventToSend) + components.analytics.metrics.track(eventToSend) } fun expand() { @@ -261,17 +290,14 @@ class TabTrayView( scrollToTab(view.context.components.core.store.state.selectedTabId) if (isPrivateModeSelected) { - container.context.components.analytics.metrics.track(Event.TabsTrayPrivateModeTapped) + components.analytics.metrics.track(Event.TabsTrayPrivateModeTapped) } else { - container.context.components.analytics.metrics.track(Event.TabsTrayNormalModeTapped) + components.analytics.metrics.track(Event.TabsTrayNormalModeTapped) } } - override fun onTabReselected(tab: TabLayout.Tab?) { /*noop*/ - } - - override fun onTabUnselected(tab: TabLayout.Tab?) { /*noop*/ - } + override fun onTabReselected(tab: TabLayout.Tab?) = Unit + override fun onTabUnselected(tab: TabLayout.Tab?) = Unit var mode: Mode = Mode.Normal private set @@ -513,7 +539,9 @@ class TabTrayView( // We offset the tab index by the number of items in the other adapters. // We add the offset, because the layoutManager is initialized with `reverseLayout`. - val recyclerViewIndex = selectedBrowserTabIndex + collectionsButtonAdapter.itemCount + val recyclerViewIndex = selectedBrowserTabIndex + + collectionsButtonAdapter.itemCount + + syncedTabsController.adapter.itemCount layoutManager?.scrollToPosition(recyclerViewIndex) } diff --git a/app/src/main/res/anim/full_rotation.xml b/app/src/main/res/anim/full_rotation.xml new file mode 100644 index 000000000..357a54041 --- /dev/null +++ b/app/src/main/res/anim/full_rotation.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/sync_tabs_error_row.xml b/app/src/main/res/layout/sync_tabs_error_row.xml index f9005af30..1e104150e 100644 --- a/app/src/main/res/layout/sync_tabs_error_row.xml +++ b/app/src/main/res/layout/sync_tabs_error_row.xml @@ -19,6 +19,7 @@ android:layout_marginTop="4dp" android:textSize="14sp" android:textAlignment="viewStart" + android:textColor="@color/tab_tray_item_text_normal_theme" tools:text="@string/synced_tabs_no_tabs"/> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_synced_tabs_title.xml b/app/src/main/res/layout/view_synced_tabs_title.xml new file mode 100644 index 000000000..eedbe9415 --- /dev/null +++ b/app/src/main/res/layout/view_synced_tabs_title.xml @@ -0,0 +1,29 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/org/mozilla/fenix/sync/ListenerDelegateTest.kt b/app/src/test/java/org/mozilla/fenix/sync/ListenerDelegateTest.kt new file mode 100644 index 000000000..f1863bd60 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/sync/ListenerDelegateTest.kt @@ -0,0 +1,26 @@ +/* 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.sync + +import io.mockk.mockk +import io.mockk.verify +import mozilla.components.feature.syncedtabs.view.SyncedTabsView +import org.junit.Test + +class ListenerDelegateTest { + @Test + fun `delegate invokes nullable listener`() { + val listener: SyncedTabsView.Listener? = mockk(relaxed = true) + val delegate = ListenerDelegate { listener } + + delegate.onRefresh() + + verify { listener?.onRefresh() } + + delegate.onTabClicked(mockk()) + + verify { listener?.onTabClicked(any()) } + } +} diff --git a/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsAdapterTest.kt b/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsAdapterTest.kt index e22bbb181..f1f7f3fea 100644 --- a/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsAdapterTest.kt +++ b/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsAdapterTest.kt @@ -11,6 +11,7 @@ import mozilla.components.browser.storage.sync.SyncedDeviceTabs import mozilla.components.browser.storage.sync.Tab import mozilla.components.browser.storage.sync.TabEntry import mozilla.components.concept.sync.DeviceType +import mozilla.components.feature.syncedtabs.view.SyncedTabsView import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Before @@ -21,7 +22,7 @@ import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class SyncedTabsAdapterTest { - private lateinit var listener: (Tab) -> Unit + private lateinit var listener: SyncedTabsView.Listener private lateinit var adapter: SyncedTabsAdapter private val oneTabDevice = SyncedDeviceTabs( @@ -77,10 +78,12 @@ class SyncedTabsAdapterTest { fun `updateData() adds items for each device and tab`() { assertEquals(0, adapter.itemCount) - adapter.updateData(listOf( - oneTabDevice, - threeTabDevice - )) + adapter.updateData( + listOf( + oneTabDevice, + threeTabDevice + ) + ) assertEquals(5, adapter.itemCount) assertEquals(SyncedTabsViewHolder.DeviceViewHolder.LAYOUT_ID, adapter.getItemViewType(0)) diff --git a/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsLayoutTest.kt b/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsLayoutTest.kt index a04bfbb51..8c1f6514a 100644 --- a/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsLayoutTest.kt +++ b/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsLayoutTest.kt @@ -4,16 +4,10 @@ package org.mozilla.fenix.sync -import androidx.navigation.NavController -import io.mockk.mockk import mozilla.components.feature.syncedtabs.view.SyncedTabsView.ErrorType -import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Test -import org.mozilla.fenix.R class SyncedTabsLayoutTest { @@ -25,73 +19,4 @@ class SyncedTabsLayoutTest { assertFalse(SyncedTabsLayout.pullToRefreshEnableState(ErrorType.SYNC_NEEDS_REAUTHENTICATION)) assertFalse(SyncedTabsLayout.pullToRefreshEnableState(ErrorType.SYNC_UNAVAILABLE)) } - - @Test - fun `string resource for error`() { - assertEquals( - R.string.synced_tabs_connect_another_device, - SyncedTabsLayout.stringResourceForError(ErrorType.MULTIPLE_DEVICES_UNAVAILABLE) - ) - assertEquals( - R.string.synced_tabs_enable_tab_syncing, - SyncedTabsLayout.stringResourceForError(ErrorType.SYNC_ENGINE_UNAVAILABLE) - ) - assertEquals( - R.string.synced_tabs_sign_in_message, - SyncedTabsLayout.stringResourceForError(ErrorType.SYNC_UNAVAILABLE) - ) - assertEquals( - R.string.synced_tabs_reauth, - SyncedTabsLayout.stringResourceForError(ErrorType.SYNC_NEEDS_REAUTHENTICATION) - ) - assertEquals( - R.string.synced_tabs_no_tabs, - SyncedTabsLayout.stringResourceForError(ErrorType.NO_TABS_AVAILABLE) - ) - } - - @Test - fun `get error item`() { - val navController = mockk() - - var errorItem = SyncedTabsLayout.getErrorItem( - navController, - ErrorType.MULTIPLE_DEVICES_UNAVAILABLE, - R.string.synced_tabs_connect_another_device - ) - assertNull((errorItem as SyncedTabsAdapter.AdapterItem.Error).navController) - assertEquals(R.string.synced_tabs_connect_another_device, errorItem.descriptionResId) - - errorItem = SyncedTabsLayout.getErrorItem( - navController, - ErrorType.SYNC_ENGINE_UNAVAILABLE, - R.string.synced_tabs_enable_tab_syncing - ) - assertNull((errorItem as SyncedTabsAdapter.AdapterItem.Error).navController) - assertEquals(R.string.synced_tabs_enable_tab_syncing, errorItem.descriptionResId) - - errorItem = SyncedTabsLayout.getErrorItem( - navController, - ErrorType.SYNC_NEEDS_REAUTHENTICATION, - R.string.synced_tabs_reauth - ) - assertNull((errorItem as SyncedTabsAdapter.AdapterItem.Error).navController) - assertEquals(R.string.synced_tabs_reauth, errorItem.descriptionResId) - - errorItem = SyncedTabsLayout.getErrorItem( - navController, - ErrorType.NO_TABS_AVAILABLE, - R.string.synced_tabs_no_tabs - ) - assertNull((errorItem as SyncedTabsAdapter.AdapterItem.Error).navController) - assertEquals(R.string.synced_tabs_no_tabs, errorItem.descriptionResId) - - errorItem = SyncedTabsLayout.getErrorItem( - navController, - ErrorType.SYNC_UNAVAILABLE, - R.string.synced_tabs_sign_in_message - ) - assertNotNull((errorItem as SyncedTabsAdapter.AdapterItem.Error).navController) - assertEquals(R.string.synced_tabs_sign_in_message, errorItem.descriptionResId) - } } diff --git a/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsViewHolderTest.kt index b81a0fc3b..3f8b06fd2 100644 --- a/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsViewHolderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/sync/SyncedTabsViewHolderTest.kt @@ -7,15 +7,18 @@ package org.mozilla.fenix.sync import android.view.LayoutInflater import android.view.View import android.widget.TextView +import io.mockk.Called import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.android.synthetic.main.sync_tabs_list_item.view.* import kotlinx.android.synthetic.main.view_synced_tabs_group.view.* +import kotlinx.android.synthetic.main.view_synced_tabs_title.view.* import mozilla.components.browser.storage.sync.Tab import mozilla.components.browser.storage.sync.TabEntry import mozilla.components.concept.sync.Device import mozilla.components.concept.sync.DeviceType +import mozilla.components.feature.syncedtabs.view.SyncedTabsView import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Before @@ -32,6 +35,10 @@ class SyncedTabsViewHolderTest { private lateinit var deviceViewHolder: SyncedTabsViewHolder.DeviceViewHolder private lateinit var deviceView: View private lateinit var deviceViewGroupName: TextView + private lateinit var titleView: View + private lateinit var titleViewHolder: SyncedTabsViewHolder.TitleViewHolder + private lateinit var noTabsView: View + private lateinit var noTabsViewHolder: SyncedTabsViewHolder.NoTabsViewHolder private val tab = Tab( history = listOf( @@ -59,6 +66,12 @@ class SyncedTabsViewHolderTest { every { synced_tabs_group_name } returns deviceViewGroupName } deviceViewHolder = SyncedTabsViewHolder.DeviceViewHolder(deviceView) + + titleView = inflater.inflate(SyncedTabsViewHolder.TitleViewHolder.LAYOUT_ID, null) + titleViewHolder = SyncedTabsViewHolder.TitleViewHolder(titleView) + + noTabsView = inflater.inflate(SyncedTabsViewHolder.NoTabsViewHolder.LAYOUT_ID, null) + noTabsViewHolder = SyncedTabsViewHolder.NoTabsViewHolder(noTabsView) } @Test @@ -71,11 +84,11 @@ class SyncedTabsViewHolderTest { @Test fun `TabViewHolder calls interactor on click`() { - val interactor = mockk<(Tab) -> Unit>(relaxed = true) + val interactor = mockk(relaxed = true) tabViewHolder.bind(SyncedTabsAdapter.AdapterItem.Tab(tab), interactor) tabView.performClick() - verify { interactor(tab) } + verify { interactor.onTabClicked(tab) } } @Test @@ -109,4 +122,28 @@ class SyncedTabsViewHolderTest { ) } } + + @Test + fun `TitleViewHolder calls interactor refresh`() { + val interactor = mockk(relaxed = true) + titleViewHolder.bind(SyncedTabsAdapter.AdapterItem.Title, interactor) + + titleView.findViewById(R.id.refresh_icon).performClick() + + verify { interactor.onRefresh() } + } + + @Test + fun `NoTabsViewHolder does nothing`() { + val device = mockk { + every { displayName } returns "Charcoal" + every { deviceType } returns DeviceType.DESKTOP + } + val interactor = mockk(relaxed = true) + noTabsViewHolder.bind(SyncedTabsAdapter.AdapterItem.NoTabs(device), interactor) + + titleView.performClick() + + verify { interactor wasNot Called } + } } diff --git a/app/src/test/java/org/mozilla/fenix/sync/ext/ErrorTypeKtTest.kt b/app/src/test/java/org/mozilla/fenix/sync/ext/ErrorTypeKtTest.kt new file mode 100644 index 000000000..180ed0878 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/sync/ext/ErrorTypeKtTest.kt @@ -0,0 +1,72 @@ +package org.mozilla.fenix.sync.ext + +import org.junit.Test +import androidx.navigation.NavController +import io.mockk.mockk +import mozilla.components.feature.syncedtabs.view.SyncedTabsView.ErrorType +import org.mozilla.fenix.R +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertEquals + +class ErrorTypeKtTest { + + @Test + fun `string resource for error`() { + assertEquals( + R.string.synced_tabs_connect_another_device, + ErrorType.MULTIPLE_DEVICES_UNAVAILABLE.toStringRes() + ) + assertEquals( + R.string.synced_tabs_enable_tab_syncing, + ErrorType.SYNC_ENGINE_UNAVAILABLE.toStringRes() + ) + assertEquals( + R.string.synced_tabs_sign_in_message, + ErrorType.SYNC_UNAVAILABLE.toStringRes() + ) + assertEquals( + R.string.synced_tabs_reauth, + ErrorType.SYNC_NEEDS_REAUTHENTICATION.toStringRes() + ) + assertEquals( + R.string.synced_tabs_no_tabs, + ErrorType.NO_TABS_AVAILABLE.toStringRes() + ) + } + + @Test + fun `get error item`() { + val navController = mockk() + + var errorItem = ErrorType.MULTIPLE_DEVICES_UNAVAILABLE.toAdapterItem( + R.string.synced_tabs_connect_another_device, navController + ) + assertNull(errorItem.navController) + assertEquals(R.string.synced_tabs_connect_another_device, errorItem.descriptionResId) + + errorItem = ErrorType.SYNC_ENGINE_UNAVAILABLE.toAdapterItem( + R.string.synced_tabs_enable_tab_syncing, navController + ) + assertNull(errorItem.navController) + assertEquals(R.string.synced_tabs_enable_tab_syncing, errorItem.descriptionResId) + + errorItem = ErrorType.SYNC_NEEDS_REAUTHENTICATION.toAdapterItem( + R.string.synced_tabs_reauth, navController + ) + assertNull(errorItem.navController) + assertEquals(R.string.synced_tabs_reauth, errorItem.descriptionResId) + + errorItem = ErrorType.NO_TABS_AVAILABLE.toAdapterItem( + R.string.synced_tabs_no_tabs, navController + ) + assertNull(errorItem.navController) + assertEquals(R.string.synced_tabs_no_tabs, errorItem.descriptionResId) + + errorItem = ErrorType.SYNC_UNAVAILABLE.toAdapterItem( + R.string.synced_tabs_sign_in_message, navController + ) + assertNotNull(errorItem.navController) + assertEquals(R.string.synced_tabs_sign_in_message, errorItem.descriptionResId) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt b/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt new file mode 100644 index 000000000..bc04fc8f7 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt @@ -0,0 +1,92 @@ +/* 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.sync.ext + +import io.mockk.every +import io.mockk.mockk +import mozilla.components.browser.storage.sync.SyncedDeviceTabs +import mozilla.components.browser.storage.sync.Tab +import mozilla.components.browser.storage.sync.TabEntry +import mozilla.components.concept.sync.DeviceType +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import org.mozilla.fenix.sync.SyncedTabsAdapter + +class SyncedTabsAdapterKtTest { + private val noTabDevice = SyncedDeviceTabs( + device = mockk { + every { displayName } returns "Charcoal" + every { deviceType } returns DeviceType.DESKTOP + }, + tabs = emptyList() + ) + + private val oneTabDevice = SyncedDeviceTabs( + device = mockk { + every { displayName } returns "Charcoal" + every { deviceType } returns DeviceType.DESKTOP + }, + tabs = listOf(Tab( + history = listOf(TabEntry( + title = "Mozilla", + url = "https://mozilla.org", + iconUrl = null + )), + active = 0, + lastUsed = 0L + )) + ) + + private val twoTabDevice = SyncedDeviceTabs( + device = mockk { + every { displayName } returns "Emerald" + every { deviceType } returns DeviceType.MOBILE + }, + tabs = listOf( + Tab( + history = listOf(TabEntry( + title = "Mozilla", + url = "https://mozilla.org", + iconUrl = null + )), + active = 0, + lastUsed = 0L + ), + Tab( + history = listOf( + TabEntry( + title = "Firefox", + url = "https://firefox.com", + iconUrl = null + ) + ), + active = 0, + lastUsed = 0L + ) + ) + ) + + @Test + fun `verify ordering of adapter items`() { + val syncedDeviceList = listOf(oneTabDevice, twoTabDevice) + val adapterData = syncedDeviceList.toAdapterList() + + assertEquals(5, adapterData.count()) + assertTrue(adapterData[0] is SyncedTabsAdapter.AdapterItem.Device) + assertTrue(adapterData[1] is SyncedTabsAdapter.AdapterItem.Tab) + assertTrue(adapterData[2] is SyncedTabsAdapter.AdapterItem.Device) + assertTrue(adapterData[3] is SyncedTabsAdapter.AdapterItem.Tab) + assertTrue(adapterData[4] is SyncedTabsAdapter.AdapterItem.Tab) + } + + @Test + fun `verify no tabs displayed`() { + val syncedDeviceList = listOf(noTabDevice) + val adapterData = syncedDeviceList.toAdapterList() + + assertEquals(0, adapterData.count()) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt index 57ce54da4..c95c8bef4 100644 --- a/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt @@ -26,6 +26,8 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test +import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager @@ -34,6 +36,7 @@ import org.mozilla.fenix.ext.sessionsOfType @OptIn(ExperimentalCoroutinesApi::class) class DefaultTabTrayControllerTest { + private val activity: HomeActivity = mockk(relaxed = true) private val profiler: Profiler? = mockk(relaxed = true) private val navController: NavController = mockk() private val sessionManager: SessionManager = mockk(relaxed = true) @@ -81,6 +84,7 @@ class DefaultTabTrayControllerTest { every { tabCollection.title } returns "Collection title" controller = DefaultTabTrayController( + activity = activity, profiler = profiler, sessionManager = sessionManager, browsingModeManager = browsingModeManager, @@ -156,6 +160,15 @@ class DefaultTabTrayControllerTest { } } + @Test + fun onSyncedTabClicked() { + controller.onSyncedTabClicked(mockk(relaxed = true)) + + verify { + activity.openToBrowserAndLoad(any(), true, BrowserDirection.FromTabTray) + } + } + @Test fun handleBackPressed() { every { tabTrayFragmentStore.state.mode } returns TabTrayDialogFragmentState.Mode.MultiSelect( diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt new file mode 100644 index 000000000..c3d7b33de --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt @@ -0,0 +1,78 @@ +package org.mozilla.fenix.tabtray + +import android.view.LayoutInflater +import android.view.View +import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runBlockingTest +import mozilla.components.browser.storage.sync.SyncedDeviceTabs +import mozilla.components.feature.syncedtabs.view.SyncedTabsView.ErrorType +import mozilla.components.support.test.robolectric.testContext +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 +import org.mozilla.fenix.sync.SyncedTabsViewHolder + +@ExperimentalCoroutinesApi +@RunWith(FenixRobolectricTestRunner::class) +class SyncedTabsControllerTest { + + private lateinit var view: View + private lateinit var controller: SyncedTabsController + + @Before + fun setup() = runBlockingTest { + view = LayoutInflater.from(testContext).inflate(R.layout.about_list_item, null) + controller = SyncedTabsController(view, coroutineContext) + } + + @Test + fun `display synced tabs in reverse`() { + val tabs = listOf( + SyncedDeviceTabs( + device = mockk(relaxed = true), + tabs = listOf( + mockk(relaxed = true), + mockk(relaxed = true) + ) + ) + ) + + controller.displaySyncedTabs(tabs) + + val itemCount = controller.adapter.itemCount + + // title + device name + 2 tabs + assertEquals(4, itemCount) + assertEquals( + SyncedTabsViewHolder.TitleViewHolder.LAYOUT_ID, + controller.adapter.getItemViewType(itemCount - 1) + ) + assertEquals( + SyncedTabsViewHolder.DeviceViewHolder.LAYOUT_ID, + controller.adapter.getItemViewType(itemCount - 2) + ) + assertEquals( + SyncedTabsViewHolder.TabViewHolder.LAYOUT_ID, + controller.adapter.getItemViewType(itemCount - 3) + ) + assertEquals( + SyncedTabsViewHolder.TabViewHolder.LAYOUT_ID, + controller.adapter.getItemViewType(itemCount - 4) + ) + } + + @Test + fun `show error when we go kaput`() { + controller.onError(ErrorType.SYNC_NEEDS_REAUTHENTICATION) + + assertEquals(1, controller.adapter.itemCount) + assertEquals( + SyncedTabsViewHolder.ErrorViewHolder.LAYOUT_ID, + controller.adapter.getItemViewType(0) + ) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt index 8a459f73f..575b3a4ec 100644 --- a/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt @@ -53,6 +53,12 @@ class TabTrayFragmentInteractorTest { verify { controller.onCloseAllTabsClicked(true) } } + @Test + fun onSyncedTabClicked() { + interactor.onSyncedTabClicked(mockk(relaxed = true)) + verify { controller.onSyncedTabClicked(any()) } + } + @Test fun onBackPressed() { interactor.onBackPressed() From b54b743d83d7843e17fa3376f5fce9895a4c74e3 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Tue, 18 Aug 2020 01:15:08 -0400 Subject: [PATCH 013/128] For #12287: Show devices with no tabs in Synced Tabs list --- .../fenix/sync/ext/SyncedTabsAdapter.kt | 20 +++++++++---------- .../main/res/layout/sync_tabs_list_item.xml | 13 +----------- .../res/layout/view_synced_tabs_no_item.xml | 14 ++++++++++++- app/src/main/res/values/strings.xml | 2 ++ .../fenix/sync/ext/SyncedTabsAdapterKtTest.kt | 4 +++- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt index 6f1e982b5..18c2c1be9 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapter.kt @@ -7,16 +7,16 @@ package org.mozilla.fenix.sync.ext import mozilla.components.browser.storage.sync.SyncedDeviceTabs import org.mozilla.fenix.sync.SyncedTabsAdapter.AdapterItem -fun List.toAdapterList( -): MutableList { - val allDeviceTabs = mutableListOf() +/** + * Converts a list of [SyncedDeviceTabs] into a list of [AdapterItem]. + */ +fun List.toAdapterList() = asSequence().flatMap { (device, tabs) -> - forEach { (device, tabs) -> - if (tabs.isNotEmpty()) { - allDeviceTabs.add(AdapterItem.Device(device)) - tabs.mapTo(allDeviceTabs) { AdapterItem.Tab(it) } - } + val deviceTabs = if (tabs.isEmpty()) { + sequenceOf(AdapterItem.NoTabs(device)) + } else { + tabs.asSequence().map { AdapterItem.Tab(it) } } - return allDeviceTabs -} \ No newline at end of file + sequenceOf(AdapterItem.Device(device)) + deviceTabs +}.toList() diff --git a/app/src/main/res/layout/sync_tabs_list_item.xml b/app/src/main/res/layout/sync_tabs_list_item.xml index 99e776393..cb797ca34 100644 --- a/app/src/main/res/layout/sync_tabs_list_item.xml +++ b/app/src/main/res/layout/sync_tabs_list_item.xml @@ -8,6 +8,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="8dp" android:background="?android:attr/selectableItemBackground"> - - diff --git a/app/src/main/res/layout/view_synced_tabs_no_item.xml b/app/src/main/res/layout/view_synced_tabs_no_item.xml index fbb5f13e9..769081cd6 100644 --- a/app/src/main/res/layout/view_synced_tabs_no_item.xml +++ b/app/src/main/res/layout/view_synced_tabs_no_item.xml @@ -4,6 +4,18 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + android:layout_height="wrap_content" + android:paddingBottom="24dp"> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b3e512f7..e83485f4d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1455,6 +1455,8 @@ View a list of tabs from your other devices. Sign in to sync + + No open tabs diff --git a/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt b/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt index bc04fc8f7..aa568acdd 100644 --- a/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt +++ b/app/src/test/java/org/mozilla/fenix/sync/ext/SyncedTabsAdapterKtTest.kt @@ -87,6 +87,8 @@ class SyncedTabsAdapterKtTest { val syncedDeviceList = listOf(noTabDevice) val adapterData = syncedDeviceList.toAdapterList() - assertEquals(0, adapterData.count()) + assertEquals(2, adapterData.count()) + assertTrue(adapterData[0] is SyncedTabsAdapter.AdapterItem.Device) + assertTrue(adapterData[1] is SyncedTabsAdapter.AdapterItem.NoTabs) } } From f92485d1e862c8194619ca7ac21b6f3e8a18d283 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Tue, 18 Aug 2020 01:45:48 -0400 Subject: [PATCH 014/128] For #12287: Add feature flag for Synced Tabs in tabs tray --- .../java/org/mozilla/fenix/FeatureFlags.kt | 11 +++----- .../fenix/components/BackgroundServices.kt | 11 ++------ .../components/toolbar/DefaultToolbarMenu.kt | 5 ++-- .../java/org/mozilla/fenix/home/HomeMenu.kt | 3 +-- .../fenix/settings/SecretSettingsFragment.kt | 6 +++++ .../account/AccountSettingsFragment.kt | 4 +-- .../mozilla/fenix/sync/SyncedTabsFragment.kt | 6 +++++ .../mozilla/fenix/sync/SyncedTabsLayout.kt | 4 +++ .../org/mozilla/fenix/tabtray/TabTrayView.kt | 26 ++++++++++--------- .../java/org/mozilla/fenix/utils/Settings.kt | 6 +++++ app/src/main/res/values/preference_keys.xml | 2 ++ app/src/main/res/values/static_strings.xml | 2 ++ .../res/xml/account_settings_preferences.xml | 1 - .../res/xml/secret_settings_preferences.xml | 5 ++++ 14 files changed, 56 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index 1a3d4d01d..352f44a44 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -20,14 +20,11 @@ object FeatureFlags { const val loginsEdit = true /** - * Enable tab sync feature + * Shows Synced Tabs in the tabs tray. + * + * Tracking issue: https://github.com/mozilla-mobile/fenix/issues/13892 */ - const val syncedTabs = true - - /** - * Enables new tab tray pref - */ - val tabTray = Config.channel.isNightlyOrDebug + val syncedTabsInTabsTray = Config.channel.isNightlyOrDebug /** * Enables viewing tab history diff --git a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt index f4b5a7710..44f4131fe 100644 --- a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt +++ b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt @@ -32,7 +32,6 @@ import mozilla.components.service.fxa.sync.GlobalSyncableStoreProvider import mozilla.components.service.sync.logins.SyncableLoginsStorage import mozilla.components.support.utils.RunWhenReadyQueue import org.mozilla.fenix.Config -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController @@ -85,11 +84,8 @@ class BackgroundServices( ) @VisibleForTesting - val supportedEngines = if (FeatureFlags.syncedTabs) { + val supportedEngines = setOf(SyncEngine.History, SyncEngine.Bookmarks, SyncEngine.Passwords, SyncEngine.Tabs) - } else { - setOf(SyncEngine.History, SyncEngine.Bookmarks, SyncEngine.Passwords) - } private val syncConfig = SyncConfig(supportedEngines, syncPeriodInMinutes = 240L) // four hours init { @@ -98,10 +94,7 @@ class BackgroundServices( GlobalSyncableStoreProvider.configureStore(SyncEngine.History to historyStorage) GlobalSyncableStoreProvider.configureStore(SyncEngine.Bookmarks to bookmarkStorage) GlobalSyncableStoreProvider.configureStore(SyncEngine.Passwords to passwordsStorage) - - if (FeatureFlags.syncedTabs) { - GlobalSyncableStoreProvider.configureStore(SyncEngine.Tabs to remoteTabsStorage) - } + GlobalSyncableStoreProvider.configureStore(SyncEngine.Tabs to remoteTabsStorage) } private val telemetryAccountObserver = TelemetryAccountObserver( 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 2ee5693fe..4ae5b3f59 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 @@ -24,7 +24,6 @@ import mozilla.components.browser.state.selector.findTab import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.storage.BookmarksStorage import mozilla.components.support.ktx.android.content.getColorFromAttr -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode @@ -177,12 +176,14 @@ class DefaultToolbarMenu( ?.browsingModeManager?.mode == BrowsingMode.Normal val shouldDeleteDataOnQuit = context.components.settings .shouldDeleteBrowsingDataOnQuit + val syncedTabsInTabsTray = context.components.settings + .syncedTabsInTabsTray val menuItems = listOfNotNull( if (FeatureFlags.viewDownloads) downloadsItem else null, historyItem, bookmarksItem, - if (FeatureFlags.syncedTabs) syncedTabs else null, + if (syncedTabsInTabsTray) null else syncedTabs, settings, if (shouldDeleteDataOnQuit) deleteDataOnQuit else null, BrowserMenuDivider(), diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt index a90dc3b50..8036399ea 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt @@ -21,7 +21,6 @@ import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.OAuthAccount import mozilla.components.support.ktx.android.content.getColorFromAttr -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings @@ -167,7 +166,7 @@ class HomeMenu( if (settings.shouldDeleteBrowsingDataOnQuit) quitItem else null, settingsItem, BrowserMenuDivider(), - if (FeatureFlags.syncedTabs) syncedTabsItem else null, + if (settings.syncedTabsInTabsTray) null else syncedTabsItem, bookmarksItem, historyItem, if (FeatureFlags.viewDownloads) downloadsItem else null, diff --git a/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt index c3e663104..7040af768 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt @@ -36,5 +36,11 @@ class SecretSettingsFragment : PreferenceFragmentCompat() { isChecked = context.settings().waitToShowPageUntilFirstPaint onPreferenceChangeListener = SharedPreferenceUpdater() } + + requirePreference(R.string.pref_key_synced_tabs_tabs_tray).apply { + isVisible = FeatureFlags.syncedTabsInTabsTray + isChecked = context.settings().syncedTabsInTabsTray + onPreferenceChangeListener = SharedPreferenceUpdater() + } } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/account/AccountSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/account/AccountSettingsFragment.kt index 0eab4909c..732f89671 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/account/AccountSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/account/AccountSettingsFragment.kt @@ -36,7 +36,6 @@ import mozilla.components.service.fxa.sync.SyncStatusObserver import mozilla.components.service.fxa.sync.getLastSynced import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.util.dpToPx -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.StoreProvider @@ -271,9 +270,8 @@ class AccountSettingsFragment : PreferenceFragmentCompat() { isChecked = syncEnginesStatus.getOrElse(SyncEngine.Passwords) { true } } requirePreference(R.string.pref_key_sync_tabs).apply { - isVisible = FeatureFlags.syncedTabs isEnabled = syncEnginesStatus.containsKey(SyncEngine.Tabs) - isChecked = syncEnginesStatus.getOrElse(SyncEngine.Tabs) { FeatureFlags.syncedTabs } + isChecked = syncEnginesStatus.getOrElse(SyncEngine.Tabs) { true } } } diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsFragment.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsFragment.kt index 4059d5159..cd67fe06b 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsFragment.kt @@ -13,6 +13,7 @@ import mozilla.components.browser.storage.sync.Tab import mozilla.components.feature.syncedtabs.SyncedTabsFeature import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.ext.components @@ -22,6 +23,11 @@ import org.mozilla.fenix.library.LibraryPageFragment class SyncedTabsFragment : LibraryPageFragment() { private val syncedTabsFeature = ViewBoundFeatureWrapper() + init { + // Sanity-check: Remove this class when the feature flag is always enabled. + FeatureFlags.syncedTabsInTabsTray + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt index 1d160cfe5..2d3b5c0a4 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.launch import mozilla.components.browser.storage.sync.SyncedDeviceTabs import mozilla.components.browser.storage.sync.Tab import mozilla.components.feature.syncedtabs.view.SyncedTabsView +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.sync.ext.toAdapterItem import org.mozilla.fenix.sync.ext.toStringRes @@ -42,6 +43,9 @@ class SyncedTabsLayout @JvmOverloads constructor( synced_tabs_list.adapter = adapter synced_tabs_pull_to_refresh.setOnRefreshListener { listener?.onRefresh() } + + // Sanity-check: Remove this class when the feature flag is always enabled. + FeatureFlags.syncedTabsInTabsTray } override fun onError(error: SyncedTabsView.ErrorType) { diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt index 977cee49a..07426f456 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt @@ -145,18 +145,20 @@ class TabTrayView( setTopOffset(startingInLandscape) - syncedTabsFeature.set( - feature = SyncedTabsFeature( - context = container.context, - storage = components.backgroundServices.syncedTabsStorage, - accountManager = components.backgroundServices.accountManager, - view = syncedTabsController, - lifecycleOwner = lifecycleOwner, - onTabClicked = ::handleTabClicked - ), - owner = lifecycleOwner, - view = view - ) + if (view.context.settings().syncedTabsInTabsTray) { + syncedTabsFeature.set( + feature = SyncedTabsFeature( + context = container.context, + storage = components.backgroundServices.syncedTabsStorage, + accountManager = components.backgroundServices.accountManager, + view = syncedTabsController, + lifecycleOwner = lifecycleOwner, + onTabClicked = ::handleTabClicked + ), + owner = lifecycleOwner, + view = view + ) + } val concatAdapter = ConcatAdapter(tabsAdapter) view.tabsTray.apply { diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index 6c703a9c2..885720d07 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -109,6 +109,12 @@ class Settings(private val appContext: Context) : PreferencesHolder { featureFlag = FeatureFlags.waitUntilPaintToDraw ) + var syncedTabsInTabsTray by featureFlagPreference( + appContext.getPreferenceKey(R.string.pref_key_synced_tabs_tabs_tray), + default = false, + featureFlag = FeatureFlags.syncedTabsInTabsTray + ) + var forceEnableZoom by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_accessibility_force_enable_zoom), default = false diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 57402d075..6b0042d96 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -179,6 +179,8 @@ pref_key_wait_first_paint + pref_key_synced_tabs_tabs_tray + pref_key_debug_settings pref_key_open_tabs_count diff --git a/app/src/main/res/values/static_strings.xml b/app/src/main/res/values/static_strings.xml index e51388ca3..4a76e78b4 100644 --- a/app/src/main/res/values/static_strings.xml +++ b/app/src/main/res/values/static_strings.xml @@ -36,6 +36,8 @@ Use New Search Experience Wait Until First Paint To Show Page Content + + Show Synced Tabs in the tabs tray link diff --git a/app/src/main/res/xml/account_settings_preferences.xml b/app/src/main/res/xml/account_settings_preferences.xml index bdf69b790..0e409fbc4 100644 --- a/app/src/main/res/xml/account_settings_preferences.xml +++ b/app/src/main/res/xml/account_settings_preferences.xml @@ -43,7 +43,6 @@ diff --git a/app/src/main/res/xml/secret_settings_preferences.xml b/app/src/main/res/xml/secret_settings_preferences.xml index e8e2f95d9..794994749 100644 --- a/app/src/main/res/xml/secret_settings_preferences.xml +++ b/app/src/main/res/xml/secret_settings_preferences.xml @@ -14,4 +14,9 @@ android:key="@string/pref_key_wait_first_paint" android:title="@string/preferences_debug_settings_wait_first_paint" app:iconSpaceReserved="false" /> + From 99fab556f4c0d5c0000c7bb45665585f5782be94 Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Tue, 18 Aug 2020 18:19:11 -0400 Subject: [PATCH 015/128] For #12287: Address review comments --- .../fenix/tabtray/SyncedTabsController.kt | 30 ++++++++++ .../fenix/tabtray/TabTrayDialogFragment.kt | 1 + .../org/mozilla/fenix/tabtray/TabTrayView.kt | 5 +- app/src/main/res/anim/full_rotation.xml | 3 + .../main/res/layout/sync_tabs_list_item.xml | 4 +- .../res/layout/view_synced_tabs_title.xml | 1 + .../fenix/tabtray/SyncedTabsControllerTest.kt | 57 ++++++++++++++++++- 7 files changed, 96 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt b/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt index 2e47fff15..8fbb87c63 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt @@ -6,13 +6,21 @@ package org.mozilla.fenix.tabtray import android.view.View import androidx.fragment.app.FragmentManager.findFragment +import androidx.lifecycle.LifecycleOwner import androidx.navigation.NavController import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.ConcatAdapter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import mozilla.components.browser.storage.sync.SyncedDeviceTabs import mozilla.components.feature.syncedtabs.view.SyncedTabsView +import mozilla.components.lib.state.ext.flowScoped +import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import org.mozilla.fenix.sync.ListenerDelegate import org.mozilla.fenix.sync.SyncedTabsAdapter import org.mozilla.fenix.sync.ext.toAdapterList @@ -20,8 +28,12 @@ import org.mozilla.fenix.sync.ext.toAdapterItem import org.mozilla.fenix.sync.ext.toStringRes import kotlin.coroutines.CoroutineContext +@OptIn(ExperimentalCoroutinesApi::class) class SyncedTabsController( + lifecycleOwner: LifecycleOwner, private val view: View, + store: TabTrayDialogFragmentStore, + private val concatAdapter: ConcatAdapter, coroutineContext: CoroutineContext = Dispatchers.Main ) : SyncedTabsView { override var listener: SyncedTabsView.Listener? = null @@ -30,6 +42,24 @@ class SyncedTabsController( private val scope: CoroutineScope = CoroutineScope(coroutineContext) + init { + store.flowScoped(lifecycleOwner) { flow -> + flow.map { it.mode } + .ifChanged() + .drop(1) + .collect { mode -> + when (mode) { + is TabTrayDialogFragmentState.Mode.Normal -> { + concatAdapter.addAdapter(0, adapter) + } + is TabTrayDialogFragmentState.Mode.MultiSelect -> { + concatAdapter.removeAdapter(adapter) + } + } + } + } + } + override fun displaySyncedTabs(syncedTabs: List) { scope.launch { val tabsList = listOf(SyncedTabsAdapter.AdapterItem.Title) + syncedTabs.toAdapterList() diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt index be5ec1818..3b64217f4 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt @@ -192,6 +192,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler showAddNewCollectionDialog = ::showAddNewCollectionDialog ) ), + store = tabTrayDialogStore, isPrivate = isPrivate, startingInLandscape = requireContext().resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE, diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt index 07426f456..76574c692 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt @@ -60,6 +60,7 @@ class TabTrayView( private val container: ViewGroup, private val tabsAdapter: FenixTabsAdapter, private val interactor: TabTrayInteractor, + store: TabTrayDialogFragmentStore, isPrivate: Boolean, startingInLandscape: Boolean, lifecycleOwner: LifecycleOwner, @@ -78,13 +79,14 @@ class TabTrayView( private val behavior = BottomSheetBehavior.from(view.tab_wrapper) + private val concatAdapter = ConcatAdapter(tabsAdapter) private val tabTrayItemMenu: TabTrayItemMenu private var menu: BrowserMenu? = null private var tabsTouchHelper: TabsTouchHelper private val collectionsButtonAdapter = SaveToCollectionsButtonAdapter(interactor, isPrivate) - private val syncedTabsController = SyncedTabsController(view) + private val syncedTabsController = SyncedTabsController(lifecycleOwner, view, store, concatAdapter) private val syncedTabsFeature = ViewBoundFeatureWrapper() private var hasLoaded = false @@ -160,7 +162,6 @@ class TabTrayView( ) } - val concatAdapter = ConcatAdapter(tabsAdapter) view.tabsTray.apply { layoutManager = LinearLayoutManager(container.context).apply { reverseLayout = true diff --git a/app/src/main/res/anim/full_rotation.xml b/app/src/main/res/anim/full_rotation.xml index 357a54041..eefb51740 100644 --- a/app/src/main/res/anim/full_rotation.xml +++ b/app/src/main/res/anim/full_rotation.xml @@ -1,4 +1,7 @@ + diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt index c3d7b33de..6ff967c84 100644 --- a/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabtray/SyncedTabsControllerTest.kt @@ -2,31 +2,70 @@ package org.mozilla.fenix.tabtray import android.view.LayoutInflater import android.view.View +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.recyclerview.widget.ConcatAdapter +import io.mockk.Called +import io.mockk.every import io.mockk.mockk +import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineDispatcher import kotlinx.coroutines.test.runBlockingTest import mozilla.components.browser.storage.sync.SyncedDeviceTabs import mozilla.components.feature.syncedtabs.view.SyncedTabsView.ErrorType +import mozilla.components.support.test.ext.joinBlocking import mozilla.components.support.test.robolectric.testContext +import mozilla.components.support.test.rule.MainCoroutineRule import org.junit.Assert.assertEquals import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.R import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.sync.SyncedTabsViewHolder +import org.mozilla.fenix.tabtray.TabTrayDialogFragmentAction.EnterMultiSelectMode +import org.mozilla.fenix.tabtray.TabTrayDialogFragmentAction.ExitMultiSelectMode +import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode @ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class SyncedTabsControllerTest { + private val testDispatcher = TestCoroutineDispatcher() + @get:Rule + val coroutinesTestRule = MainCoroutineRule(testDispatcher) + private lateinit var view: View private lateinit var controller: SyncedTabsController + private lateinit var lifecycleOwner: LifecycleOwner + private lateinit var lifecycle: LifecycleRegistry + private lateinit var concatAdapter: ConcatAdapter + private lateinit var store: TabTrayDialogFragmentStore @Before fun setup() = runBlockingTest { + lifecycleOwner = mockk() + lifecycle = LifecycleRegistry(lifecycleOwner) + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) + every { lifecycleOwner.lifecycle } returns lifecycle + + concatAdapter = mockk() + every { concatAdapter.addAdapter(any(), any()) } returns true + every { concatAdapter.removeAdapter(any()) } returns true + + store = TabTrayDialogFragmentStore( + initialState = TabTrayDialogFragmentState( + mode = Mode.Normal, + browserState = mockk(relaxed = true) + ) + ) + view = LayoutInflater.from(testContext).inflate(R.layout.about_list_item, null) - controller = SyncedTabsController(view, coroutineContext) + controller = + SyncedTabsController(lifecycleOwner, view, store, concatAdapter, coroutineContext) } @Test @@ -75,4 +114,20 @@ class SyncedTabsControllerTest { controller.adapter.getItemViewType(0) ) } + + @Test + fun `do nothing on init, drop first event`() { + verify { concatAdapter wasNot Called } + } + + @Test + fun `concatAdapter updated on mode changes`() = testDispatcher.runBlockingTest { + store.dispatch(EnterMultiSelectMode).joinBlocking() + + verify { concatAdapter.removeAdapter(any()) } + + store.dispatch(ExitMultiSelectMode).joinBlocking() + + verify { concatAdapter.addAdapter(0, any()) } + } } From 3c0334141c0e2bf9142279bb3467ce62008eb9f6 Mon Sep 17 00:00:00 2001 From: Kate Glazko Date: Wed, 19 Aug 2020 14:48:22 -0700 Subject: [PATCH 016/128] No Issue: Fix Lint Issues Downloads Manager --- .../mozilla/fenix/library/downloads/DownloadAdapter.kt | 1 - .../mozilla/fenix/library/downloads/DownloadController.kt | 1 - .../fenix/library/downloads/DownloadFragmentStore.kt | 8 +++++++- .../org/mozilla/fenix/library/downloads/DownloadView.kt | 2 -- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt index 95ce6f247..71fc6d0f4 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdapter.kt @@ -1,4 +1,3 @@ - /* 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/. */ diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt index 9cc676272..ccd30c136 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt @@ -1,4 +1,3 @@ - /* 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/. */ diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt index 2078064a7..c79d45027 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragmentStore.kt @@ -16,7 +16,13 @@ import mozilla.components.lib.state.Store * @property size The size in bytes of the download item * @property contentType The type of file the download is */ -data class DownloadItem(val id: Long, val fileName: String?, val filePath: String, val size: String, val contentType: String?) +data class DownloadItem( + val id: Long, + val fileName: String?, + val filePath: String, + val size: String, + val contentType: String? +) /** * The [Store] for holding the [DownloadFragmentState] and applying [DownloadFragmentAction]s. diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt index 3261ee91e..809d8ff53 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt @@ -1,5 +1,3 @@ - - /* 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/. */ From 0de8aedd6f9ce39e5d8e59a21b5fd22f4739a8ee Mon Sep 17 00:00:00 2001 From: Jonathan Almeida Date: Wed, 19 Aug 2020 18:03:25 -0400 Subject: [PATCH 017/128] No issue: Fix missing FeatureFlags imports --- .../org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt | 1 + app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt | 1 + 2 files changed, 2 insertions(+) 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 4ae5b3f59..ff549ffa2 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 @@ -24,6 +24,7 @@ import mozilla.components.browser.state.selector.findTab import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.storage.BookmarksStorage import mozilla.components.support.ktx.android.content.getColorFromAttr +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt index 8036399ea..579e4bf95 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt @@ -21,6 +21,7 @@ import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.OAuthAccount import mozilla.components.support.ktx.android.content.getColorFromAttr +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings From 86c5a38ed82b25ffb9cc551d698aeeacbf9554ab Mon Sep 17 00:00:00 2001 From: Kate Glazko Date: Wed, 19 Aug 2020 15:45:08 -0700 Subject: [PATCH 018/128] For #13939: Missing empty state for downloads view --- .../mozilla/fenix/library/downloads/DownloadView.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt index 809d8ff53..89bfe9172 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt @@ -7,8 +7,10 @@ package org.mozilla.fenix.library.downloads import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator +import kotlinx.android.synthetic.main.component_downloads.* import kotlinx.android.synthetic.main.component_downloads.view.* import mozilla.components.support.base.feature.UserInteractionHandler import org.mozilla.fenix.R @@ -58,6 +60,8 @@ class DownloadView( state.mode === DownloadFragmentState.Mode.Normal mode = state.mode + updateEmptyState(state.items.isNotEmpty()) + downloadAdapter.updateMode(state.mode) downloadAdapter.updateDownloads(state.items) @@ -66,6 +70,14 @@ class DownloadView( ) } + fun updateEmptyState(userHasDownloads: Boolean) { + download_list.isVisible = userHasDownloads + download_empty_view.isVisible = !userHasDownloads + if (!userHasDownloads) { + download_empty_view.announceForAccessibility(context.getString(R.string.download_empty_message)) + } + } + override fun onBackPressed(): Boolean { return interactor.onBackPressed() } From 35d585d7acfebeb152f1f79afeb05cdeb768ef9b Mon Sep 17 00:00:00 2001 From: MickeyMoz Date: Wed, 19 Aug 2020 19:44:46 +0000 Subject: [PATCH 019/128] Update Android Components version to 56.0.20200819190136. --- 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 1560073ba..ff43297b6 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 = "54.0.20200818130156" + const val VERSION = "56.0.20200819190136" } From e4e16bc4453ab652a4142a391ee696eb43ec4adc Mon Sep 17 00:00:00 2001 From: Mozilla L10n Automation Bot Date: Thu, 20 Aug 2020 00:10:30 +0000 Subject: [PATCH 020/128] Import l10n. --- app/src/main/res/values-ast/strings.xml | 16 ++++++ app/src/main/res/values-cak/strings.xml | 27 +++++---- app/src/main/res/values-el/strings.xml | 64 ++++++++++++++++++++++ app/src/main/res/values-fy-rNL/strings.xml | 45 ++++++++++----- app/src/main/res/values-rm/strings.xml | 60 ++++++++++++++++---- 5 files changed, 176 insertions(+), 36 deletions(-) diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 94f1bff1b..a2e72cc6b 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -27,6 +27,8 @@ %1$d esbillaes + + Amiestu d\'una coleción nueva Nome @@ -247,6 +249,8 @@ Sincroniza los marcadores, l\'historial y muncho más cola to cuenta de Firefox Cuenta de Firefox + + Reconéutate pa siguir cola sincronización Llingua @@ -364,6 +368,11 @@ Activación de Sync + + Aniciar sesión pa reconeutar + + Desaniciar la cuenta + firefox.com/pair]]> @@ -473,6 +482,9 @@ %1$s (en privao) + + Guardar + Desaniciar l\'historial @@ -659,6 +671,8 @@ Esbillóse %d llingüeta ¡Guardáronse les llingüetes! + + ¡Guardóse la coleición! ¡Guardóse la llingüeta! @@ -690,6 +704,8 @@ Unviar a tolos preseos + + Reconexón con Sync Coneutar otru preséu diff --git a/app/src/main/res/values-cak/strings.xml b/app/src/main/res/values-cak/strings.xml index c333c6ea9..5fcff53bc 100644 --- a/app/src/main/res/values-cak/strings.xml +++ b/app/src/main/res/values-cak/strings.xml @@ -27,6 +27,16 @@ %1$s ruwi\' ejaqon. Tachapa\' richin nak\'ëx ruwi\'. + + %1$d xcha\' + + Titz\'aqatisäx k\'ak\'a\' mol + + B\'i\'aj + + + Ticha\' mol + %1$s b\'anon ruma Mozilla. @@ -151,14 +161,10 @@ Tiwachib\'ëx - - Choj okem Runuk\'ulem kanob\'äl - - Tikanöx pa - Wakami tikanöx rik\'in: + Wakami tikanöx rik\'in: Titz\'ajb\'äl ri ximonel pa ri molwuj @@ -270,8 +276,6 @@ Taq rusamajib\'al nuk\'unel Näj chojmirisanem pa USB - - Kek\'ut retal pitz\'b\'äl richin nikanöx Kek\'ut pe ri taq chilab\'enïk richin yakanon @@ -524,6 +528,9 @@ %1$s (Ichinan Rub\'anikil) + + Tiyak + Tiyuj natab\'äl @@ -649,7 +656,7 @@ Xyuj %1$s - + Taq yaketal xeyuj TITZOLÏX @@ -1458,9 +1465,7 @@ Achi\'el: \nhttps://www.google.com/search?q=%s K\'o chik jun tikirib\'äl molojri\'ïl rik\'in re b\'i\'aj re\' - - Tok rik\'in jun Rub\'i\' Rutaqoya\'l Firefox - + Tokisäx jun chik okisab\'äl Tajuxub\'ej chik awi\'. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 962a21a6c..a457e1d17 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -39,6 +39,9 @@ Αποθήκευση επιλεγμένων καρτελών στη συλλογή + + Τέλος λειτουργίας πολλαπλής επιλογής + Το %1$s αναπτύσσεται από τη Mozilla. @@ -231,6 +234,10 @@ Προσθήκη συντόμευσης ιδιωτικής περιήγησης Προσβασιμότητα + + Προσαρμοσμένος διακομιστής λογαριασμού Firefox + + Προσαρμοσμένος διακομιστής Sync Λογαριασμός @@ -305,6 +312,10 @@ Συγχρονισμός… + + Αποτυχία συγχρονισμού. Τελευταία επιτυχία: %s + + Αποτυχία συγχρονισμού. Τελευταίος συγχρονισμός: ποτέ Τελευταίος συγχρονισμός: %s @@ -317,6 +328,8 @@ Ληφθείσες καρτέλες + + Ειδοποιήσεις για καρτέλες που λαμβάνονται από άλλες συσκευές Firefox. Ελήφθη καρτέλα @@ -329,6 +342,8 @@ Προστασία από καταγραφή Προστασία από καταγραφή + + Φραγή περιεχομένου και σεναρίων που σας παρακολουθούν στο διαδίκτυο Εξαιρέσεις @@ -358,6 +373,8 @@ Ενεργοποίηση Sync + + Σάρωση κωδικού σύζευξης στο Firefox για υπολογιστή Σύνδεση @@ -612,8 +629,13 @@ Άκυρο URL Κανένας σελιδοδείκτης εδώ + + Το %1$s διαγράφηκε Οι σελιδοδείκτες διαγράφηκαν + + Διαγραφή επιλεγμένων φακέλων ΑΝΑΙΡΕΣΗ @@ -857,6 +879,10 @@ Διαγραφή δεδομένων περιήγησης Διαγραφή δεδομένων περιήγησης στην έξοδο + + Διαγράφει αυτόματα τα δεδομένα περιήγησης όταν επιλέγετε "Έξοδος" από το κύριο μενού + + Διαγράφει αυτόματα τα δεδομένα περιήγησης όταν επιλέγετε \"Quit\" από το κύριο μενού Έξοδος @@ -1079,6 +1105,8 @@ Τα δικαιώματά σας + + Βιβλιοθήκες ανοιχτού κώδικα που χρησιμοποιούμε Τι νέο υπάρχει στο %s Εισάγετε ξανά το PIN σας + + Ξεκλειδώστε για να δείτε τις αποθηκευμένες συνδέσεις σας Αυτή η σύνδεση δεν είναι ασφαλής. Οι λογαριασμοί που εισάγονται εδώ ενδέχεται να παραβιαστούν. @@ -1198,16 +1228,22 @@ Αντιγραφή ονόματος χρήστη Αντιγραφή ιστοσελίδας + + Άνοιγμα σελίδας στο πρόγραμμα περιήγησης Εμφάνιση κωδικού πρόσβασης Απόκρυψη κωδικού πρόσβασης + + Ξεκλειδώστε για να δείτε τις αποθηκευμένες συνδέσεις σας Αργότερα Ρύθμιση τώρα Ξεκλειδώστε τη συσκευή σας + + Ζουμ σε όλες τις ιστοσελίδες Όνομα (Α-Ω) @@ -1236,14 +1272,20 @@ Νήμα αναζήτησης προς χρήση + + Αντικαταστήστε το ερώτημα με “%s”. Παράδειγμα:\nhttps://www.google.com/search?q=%s Μάθετε περισσότερα + + Λεπτομέρειες προσαρμοσμένης μηχανής αναζήτησης Σύνδεσμος "Μάθετε περισσότερα" Εισάγετε όνομα μηχανής αναζήτησης + + Η μηχανή αναζήτησης με το όνομα “%s” υπάρχει ήδη. Εισάγετε νήμα αναζήτησης @@ -1252,8 +1294,15 @@ Δημιουργήθηκε to %s + + Το %s αποθηκεύτηκε + + Το %s διαγράφηκε + Καλώς ορίσατε στο νέο %s + + Σας περιμένει ένα πλήρως ανασχεδιασμένο πρόγραμμα περιήγησης, με βελτιωμένη απόδοση και λειτουργίες που θα σας βοηθήσουν να κάνετε περισσότερα στο διαδίκτυο.\n\nΠαρακαλούμε περιμένετε ενώ ενημερώνουμε το %s με το Ενημέρωση του %s… @@ -1263,6 +1312,8 @@ Κωδικοί πρόσβασης + + Για να το επιτρέψετε: 1. Μεταβείτε στις Ρυθμίσεις Android @@ -1301,6 +1352,12 @@ Διαγραφή Επιλογές σύνδεσης + + Το επεξεργάσιμο πεδίο κειμένου της διεύθυνσης ιστού της σύνδεσης. + + Το επεξεργάσιμο πεδίο κειμένου για το όνομα χρήστη της σύνδεσης. + + Το επεξεργάσιμο πεδίο κειμένου για τον κωδικό πρόσβασης της σύνδεσης. Αποθήκευση αλλαγών στη σύνδεση. @@ -1325,9 +1382,16 @@ Παρακαλούμε ενεργοποιήστε το συγχρονισμό καρτελών. + + Δεν έχετε καμία άλλη καρτέλα ανοικτή στο Firefox σε άλλες σας συσκευές. + + Δείτε μια λίστα καρτελών από τις άλλες συσκευές σας. Σύνδεση στο Sync + + + Έχετε φτάσει το ανώτατο όριο κορυφαίων ιστοσελίδων OK, το κατάλαβα diff --git a/app/src/main/res/values-fy-rNL/strings.xml b/app/src/main/res/values-fy-rNL/strings.xml index 520f356bb..68786bdca 100644 --- a/app/src/main/res/values-fy-rNL/strings.xml +++ b/app/src/main/res/values-fy-rNL/strings.xml @@ -25,6 +25,29 @@ %1$s iepen ljepblêden. Tik om tusken ljepblêden te wikseljen. + + %1$d selektearre + + Nije kolleksje tafoegje + + Namme + + Kolleksje selektearje + + Multiseleksjemodus ferlitte + + Selektearre ljepblêden yn kolleksje bewarje + + %1$s selektearre + + Seleksje %1$s ûngedien makke + + Multiseleksjemodus ferlitten + + Multiseleksjemodus aktivearre, selektearje ljepblêden om yn in kolleksje te bewarjen + + Selektearre + %1$s is makke troch Mozilla. @@ -150,8 +173,8 @@ Scanne - - Sykmasine + + Sykmasine Ynstellingen sykmasine @@ -282,6 +305,8 @@ Keppelingen iepenje yn apps + + Eksterne downloadbehearder Add-ons @@ -510,6 +535,9 @@ %1$s (priveemodus) + + Bewarje + Skiednis wiskje @@ -1431,9 +1459,7 @@ Der bestiet al in oanmelding mei dy brûkersnamme - - Ferbine mei in Firefox-account. - + In oar apparaat ferbine. Graach opnij autentisearje. @@ -1455,13 +1481,4 @@ OK, begrepen - - - Fluchkeppelingen - - Sykje mei - - Diskear sykje mei: - - Sykfluchkeppelingen toane diff --git a/app/src/main/res/values-rm/strings.xml b/app/src/main/res/values-rm/strings.xml index 8349f9197..c438b914b 100644 --- a/app/src/main/res/values-rm/strings.xml +++ b/app/src/main/res/values-rm/strings.xml @@ -24,6 +24,29 @@ %1$s tabs averts. Tutgar per midar tab. + + %1$d tschernids + + Agiuntar ina nova collecziun + + Num + + Tscherner ina collecziun + + Sortir dal modus da tscherna multipla + + Memorisar ils tabs tschernids en ina collecziun + + %1$s tschernì + + %1$s betg tschernì + + Sortì dal modus da tscherna multipla + + Avert il modus da tscherna multipla, tscherner ils tabs per als memorisar en ina collecziun + + Tschernì + %1$s vegn sviluppà da Mozilla. @@ -144,14 +167,12 @@ Scannar - - Scursanidas + + Maschina da tschertgar Parameters da la maschina da tschertgar - - Tschertgar cun - Questa giada, tschertgar cun: + Questa giada, tschertgar cun: Encollar la colliaziun en l\'archiv provisoric @@ -258,8 +279,8 @@ Utensils per sviluppaders Debugging a distanza via USB - - Mussar las scursanidas per tschertgas + + Mussar las maschinas da tschertgar Mussar propostas da tschertga @@ -277,6 +298,8 @@ Parameters dal conto Avrir colliaziuns en apps + + Administraziun da telechargiadas externa Supplements @@ -505,6 +528,9 @@ %1$s (modus privat) + + Memorisar + Stizzar la cronologia @@ -570,6 +596,8 @@ Tscherner in ordinatur Vuls ti propi stizzar quest ordinatur? + + %s vegn a stizzar ils elements tschernids. Stizzà %1$s @@ -624,8 +652,10 @@ Stizzà %1$s - + Stizzà ils segnapaginas + + Stizzar ils ordinaturs tschernids REVOCAR @@ -718,6 +748,8 @@ %d tab tschernì Memorisà ils tabs! + + Memorisà la collecziun! Memorisà il tab! @@ -825,6 +857,10 @@ REFUSAR Vuls ti propi stizzar %1$s? + + Cun stizzar quest tab vegn l\'entira collecziun stizzada. Ti pos da tut temp crear novas collecziuns. + + Stizzar %1$s? Stizzar @@ -1231,6 +1267,8 @@ Las infurmaziuns d\'annunzia ed ils pleds-clav betg memorisads vegnan mussadas qua. Las infurmaziuns d\'annunzia ed ils pleds-clav na vegnan betg memorisads per questas paginas. + + Stizzar tut las excepziuns Tschertgar datas d\'annunzia @@ -1270,6 +1308,8 @@ Copiar il num d\'utilisader Copiar la pagina + + Avrir la website en il navigatur Mussar il pled-clav @@ -1422,9 +1462,7 @@ Datas d\'annunzia cun quest num d\'utilisader existan gia - - Connectar cun in conto da Firefox. - + Colliar in auter apparat. Re-autentifitgescha per plaschair. From 751efb7bfbc2930fcbe5cd4a1b90f9ffca8c701e Mon Sep 17 00:00:00 2001 From: Kate Glazko Date: Wed, 19 Aug 2020 16:02:43 -0700 Subject: [PATCH 021/128] For #13940: Pull To Refresh View Causes Throbber Downloads --- .../java/org/mozilla/fenix/library/downloads/DownloadView.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt index 89bfe9172..76989458d 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadView.kt @@ -56,8 +56,7 @@ class DownloadView( fun update(state: DownloadFragmentState) { - view.swipe_refresh.isEnabled = - state.mode === DownloadFragmentState.Mode.Normal + view.swipe_refresh.isEnabled = false mode = state.mode updateEmptyState(state.items.isNotEmpty()) From 499ff83b18d1f30e5c3b5cb60de6beac7939a0ac Mon Sep 17 00:00:00 2001 From: Mugurell Date: Wed, 12 Aug 2020 14:19:42 +0300 Subject: [PATCH 022/128] For #8578 - Don't attempt to use different addons icons backgrounds After the change from AC #8054 specifying different addons icons backgrounds is not possible anymore. All favicons used all throughout the app will have the same background. --- .../java/org/mozilla/fenix/addons/AddonsManagementFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt index e6bc5e57b..20c32bc3a 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt @@ -120,7 +120,6 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) addonNameTextColor = ThemeManager.resolveAttribute(R.attr.primaryText, context), addonSummaryTextColor = ThemeManager.resolveAttribute(R.attr.secondaryText, context), sectionsTypeFace = ResourcesCompat.getFont(context, R.font.metropolis_semibold), - addonBackgroundIconColor = ThemeManager.resolveAttribute(R.attr.inset, requireContext()), addonAllowPrivateBrowsingLabelDrawableRes = R.drawable.ic_add_on_private_browsing_label ) } From feae7fff2fd525ab37fbc1105b691e1f3578977e Mon Sep 17 00:00:00 2001 From: Elise Richards Date: Thu, 20 Aug 2020 11:05:11 -0500 Subject: [PATCH 023/128] =?UTF-8?q?FNX-14498=20=E2=81=83=20For=20#9487:=20?= =?UTF-8?q?improve=20fxa=20onboarding=20manual=20sign=20in=20card=20(#1331?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace strings, add learn more, hook up button * Constrain learn more and icon to the text * View holder tests * Lint * Update homescreen ui test --- .../fenix/ui/robots/HomeScreenRobot.kt | 4 +- .../OnboardingAutomaticSignInViewHolder.kt | 4 +- .../OnboardingManualSignInViewHolder.kt | 24 +++++------ .../fenix/onboarding/OnboardingController.kt | 22 ++++++++++ .../fenix/onboarding/OnboardingInteractor.kt | 14 +++++++ .../mozilla/fenix/settings/SupportUtils.kt | 4 ++ .../ic_onboarding_avatar_anonymous_large.xml | 16 +++++++ .../layout/onboarding_automatic_signin.xml | 2 +- .../res/layout/onboarding_manual_signin.xml | 42 ++++++++++++++++--- app/src/main/res/values/strings.xml | 7 ++-- ...OnboardingAutomaticSignInViewHolderTest.kt | 14 +++---- .../OnboardingManualSignInViewHolderTest.kt | 17 +++++++- 12 files changed, 135 insertions(+), 35 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt create mode 100644 app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt create mode 100644 app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml 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 f1e24be71..8540e2a0a 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 @@ -553,11 +553,11 @@ private fun assertWelcomeHeader() = .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertGetTheMostHeader() = - onView(allOf(withText("Get the most out of Firefox Preview."))) + onView(allOf(withText("Start syncing bookmarks, passwords, and more with your Firefox account."))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertAccountsSignInButton() = - onView(ViewMatchers.withResourceName("turn_on_sync_button")) + onView(ViewMatchers.withResourceName("fxa_sign_in_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertGetToKnowHeader() = diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt index 39c49a414..c09fb31d2 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt @@ -31,9 +31,9 @@ class OnboardingAutomaticSignInViewHolder( private val headerText = view.header_text init { - view.turn_on_sync_button.setOnClickListener { + view.fxa_sign_in_button.setOnClickListener { scope.launch { - onClick(it.turn_on_sync_button) + onClick(it.fxa_sign_in_button) } } } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolder.kt index e4fa6d5a3..f7b04965a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolder.kt @@ -5,40 +5,40 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding import android.view.View -import androidx.core.content.ContextCompat import androidx.navigation.Navigation import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.onboarding_manual_signin.view.* -import mozilla.components.support.ktx.android.content.getDrawableWithTint -import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.ext.addUnderline import org.mozilla.fenix.ext.components import org.mozilla.fenix.home.HomeFragmentDirections +import org.mozilla.fenix.onboarding.OnboardingController +import org.mozilla.fenix.onboarding.OnboardingInteractor class OnboardingManualSignInViewHolder(view: View) : RecyclerView.ViewHolder(view) { private val headerText = view.header_text init { - view.turn_on_sync_button.setOnClickListener { + val interactor = OnboardingInteractor(OnboardingController(itemView.context)) + + view.fxa_sign_in_button.setOnClickListener { it.context.components.analytics.metrics.track(Event.OnboardingManualSignIn) val directions = HomeFragmentDirections.actionGlobalTurnOnSync() Navigation.findNavController(view).navigate(directions) } + + view.learn_more.addUnderline() + view.learn_more.setOnClickListener { + interactor.onLearnMoreClicked() + } } fun bind() { val context = itemView.context - - val appName = context.getString(R.string.app_name) - headerText.text = context.getString(R.string.onboarding_firefox_account_header, appName) - val icon = context.getDrawableWithTint( - R.drawable.ic_onboarding_firefox_accounts, - ContextCompat.getColor(context, R.color.white_color) - ) - headerText.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon) + headerText.text = context.getString(R.string.onboarding_firefox_account_header) } companion object { diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt new file mode 100644 index 000000000..3e1945103 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt @@ -0,0 +1,22 @@ +/* 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 new file mode 100644 index 000000000..ad11d459c --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt @@ -0,0 +1,14 @@ +/* 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/java/org/mozilla/fenix/settings/SupportUtils.kt b/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt index a1a613cc1..3e1bae04a 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt @@ -74,6 +74,10 @@ object SupportUtils { return "https://support.mozilla.org/$langTag/kb/$escapedTopic" } + fun getFirefoxAccountSumoUrl(): String { + return "https://support.mozilla.org/kb/access-mozilla-services-firefox-account" + } + fun getMozillaPageUrl(page: MozillaPage, locale: Locale = Locale.getDefault()): String { val path = page.path val langTag = getLanguageTag(locale) 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 new file mode 100644 index 000000000..422897fd9 --- /dev/null +++ b/app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/layout/onboarding_automatic_signin.xml b/app/src/main/res/layout/onboarding_automatic_signin.xml index d96855dcc..2b88fd85d 100644 --- a/app/src/main/res/layout/onboarding_automatic_signin.xml +++ b/app/src/main/res/layout/onboarding_automatic_signin.xml @@ -22,7 +22,7 @@ tools:text="@string/onboarding_firefox_account_auto_signin_header_2" />